2011-10-12 63 views
0

我认为移位运算符会移动整数的内存或者它所应用的字符的内存,但以下代码的输出对我来说是一个惊喜。C中的移位运算符的确切用法是什么?

#include <stdio.h> 
#include <stdlib.h> 
#include <stdint.h> 

int main(void) { 
    uint64_t number = 33550336; 

    unsigned char *p = (unsigned char *)&number; 
    size_t i; 
    for (i=0; i < sizeof number; ++i) 
     printf("%02x ", p[i]); 
    printf("\n"); 

    //shift operation 
    number = number<<4; 

    p = (unsigned char *)&number; 
    for (i=0; i < sizeof number; ++i) 
     printf("%02x ", p[i]); 
    printf("\n"); 

    return 0; 
} 

的系统在其上它跑是小端和产生以下输出:

00 f0 ff 01 00 00 00 00 
00 00 ff 1f 00 00 00 00 

有人可以提供一些参考移位运算符的具体工作?

+0

http://en.wikipedia.org/wiki/Bitwise_operation#Bit_shifts – etuardu

+0

左移我认为你是显示你的字节顺序错误。如果字节的顺序颠倒过来,那么它看起来是有道理的。您的代码是针对32位还是64位系统? – user957902

+0

@ user957902就像他说的那样,它在一个小端机上很有意义。 –

回答

6

我想你已经回答了你自己的问题。机器是little endian,这意味着字节存储在内存中,最低有效字节向左。所以你的记忆代表:

00 f0 ff 01 00 00 00 00 => 0x0000000001fff000 
00 00 ff 1f 00 00 00 00 => 0x000000001fff0000 

正如你所看到的,第二个与第一个值相同,左移4位。

+0

它是以大端格式输出一个字节还是以这种方式存储在内存中的“%02x”? –

+0

@Amit'printf'打印数字,字节顺序无关紧要。只有在将'uint64_t *'强制转换为'unsigned char *'并单独访问字节时才重要。 Little Endian表示**字节**的顺序是从最低有效位到最高有效位(另请参见“位的字节顺序”)。 printf仍然正确地显示这些字节的值,不管它们是如何存储的(并且你不知道它们是如何存储的,因为你只能寻址的最小单元是字节)。 – Artefacto

+0

@AmitS单个字节没有字节顺序。实际整数(答案中的右侧)存储在内存中,最低有效字节在前。所以当你将这个内存重新解释为一个字符数组时,这些字符不会被交换,因为它们只是字符,字节序不适用于单个字节,只适用于多字节类型(int,float,... )。所以char数组向你展示了它如何在内存中布局。 –

2

一切是正确的:

(1 *(256^3))+(0xff的*(256^2))+(0XF0 * 256)= 33 550 336

(0x1F的*(256^3))+(0xff的*(256^2))= 536 805 376

33 550 336 *(2^4)= 536 805 376

移位4位左相同乘以2^4。

2

我想你printf让你感到困惑。这里是值:

 33550336 = 0x01FFF000 
33550336 << 4 = 0x1FFF0000 

你现在能读你输出吗?

2

它不移位内存,但位。所以,你有数量:

00 00 00 00 01 FF F0 00 

换挡这个数字4位(一个十六进制数)的离开后,你有:

00 00 00 00 1F FF 00 00 

而这正是你得到的输出,当转换为小端。

2

循环打印字节的顺序是它们存储在内存中的顺序,并且输出在大端机器上会有所不同。如果要以十六进制打印值,只需使用%016llx。然后你就会看到你所期望的:

0000000001fff000 
000000001fff0000 

第二值由4