c中的位操作会产生意外结果

时间:2014-03-25 18:09:56

标签: c bit-manipulation

我有这个程序:

#include <stdio.h>

int main(void)
{
    unsigned char unit_id[] = { 0x2B, 0xC, 0x6B, 0x54}; // 8-bit (1 byte)
    unsigned long long int unit_id_val; //64-bit (8 bytes)
    int i;

    // loops 4 times
    for(i=0;i<sizeof(unit_id)/sizeof(char);i++){
      unit_id_val |= unit_id[i] << (8 * i);
    }

    printf("the unit id is %llu\n", unit_id_val);
    return 0;
}

十六进制到二进制转换:

0x2B = 00101011
0xC  = 00001100
0x6B = 01101011
0x54 = 01010100

unit_id_val是8个字节(我在下面使用5个字节的unit_id_val来简化事情)

1)第一次迭代8 * 0 = 0因此不发生左移:

00101011 = 00101011 << 0
00000000 00000000 00000000 00000000 00000000 |= 00101011

所以结果应该是:

00000000 00000000 00000000 00000000 00101011

2)第二次迭代8 * 1 = 8,所以将无符号字符0xC的所有位左移8:

00000000 = 00101011 << 8
00000000 00000000 00000000 00000000 00101011 |= 00000000

所以结果应该是:

00000000 00000000 00000000 00000000 00101011

3)第三次迭代8 * 2 = 16,所以左移无符号字符0x6B的所有位16:

00000000 = 01101011 << 16
00000000 00000000 00000000 00000000 00101011 |= 00000000

所以结果应该是:

00000000 00000000 00000000 00000000 00101011

4)第四次迭代8 * 3 = 24,所以将无符号字符0x54的所有位左移32:

00000000 = 01010100 << 32
00000000 00000000 00000000 00000000 00101011 |= 00000000

所以结果应该是:

00000000 00000000 00000000 00000000 00101011 

00101011是43

但是当你运行这个程序时,你得到了

1416301611

是二进制:

00010100 00010110 00110000 00010110 00010001

我不明白这里的意思。我通过在评估左移运算符&lt;&lt;之前评估主表达式operator()来遵循优先级图表。在评估赋值运算符之前!=。然而,我不明白为什么我得到了回应。

3 个答案:

答案 0 :(得分:2)

00000000 = 00101011 << 8

好的,首先你的第二个元素是0x0C(即二进制00001100而不是00101011),所以你实际上在做:

(unsigned char) 0x0C  << 8

并且此表达式的结果不是0而是0x0C00,因为按位<<运算符对其左操作数执行整数提升,因此它实际上等效于:

(int) (unsigned char) 0x0C << 8

答案 1 :(得分:1)

你永远不会初始化unit_id_val,然后你|=将你移位的字节值放入其中,所以在未初始化的值中设置的任何位仍然会被设置,所以你的输出看起来像随机的垃圾。添加

unit_id_val = 0;
在你的循环之前

此外,每当您在C中执行任何操作时,操作数总是按标准转换进行转换。特别是,这意味着任何小于int的整数类型将首先转换为int。因此,即使unsigned char仅为8位,当您执行unit_id[i] << (8 * i)时,来自unit_id[i]的8位值也将转换为int(可能是您计算机上的32位)在转变之前。对于小于C中int的整数,没有办法进行任何计算 - 即使你施放它们,它们也会被隐式转换回int。< / p>

答案 2 :(得分:0)

请参阅此行

unit_id_val |= unit_id[i] << (8 * i);
unit_id_val = unit_id_val | unit_id[i] << (8 * i);

问题是你使用的是一个只声明但未初始化的变量,我们知道在未初始化的变量中,默认值是垃圾或垃圾。所以每次都毫无疑问地会得到一些不可预测的价值。