位字段操作 - 设置一点

时间:2011-09-12 11:19:21

标签: c bit-fields

#include<stdio.h>

int main()
{
    struct s{
      int bit_fld:3;
    };
    s a;
    a.bit_fld=0x10;
    a.bit_fld =( a.bit_fld | (1<<2));
    printf("%x\n",a.bit_fld);
    return 0;
}

此程序输出fffffffc

我尝试手动计算输出,但无法获得编译器生成的输出。

bit_fld = 00010000 and (1<<2) = 0100 oring两者都会导致00010100以十六进制为0x14。 为什么我对输出的看法是错误的?帮助我理解我错在哪里。

1 个答案:

答案 0 :(得分:9)

a.bit_fld只有3位大,无法存储值0x10。行为是实现定义的,但在这种情况下,它可能存储了0。

然后1 << 2就是二元100。假设我们在第一步存储0,( a.bit_fld | (1<<2))的结果为int,值为4(二进制100)。

在带符号的2的补码3位表示中,这个位模式表示值-4,所以如果-4是将值4存储到a.bit_fld时得到的,那就不足为奇了,尽管这是实现定义的。

printf中,a.bit_fld被提升为int,然后将其作为vararg传递。 2的补码32位表示为0xfffffffc,这就是你所看到的。

对于int格式,将unsigned int而不是printf传递给%x也是未定义的行为。然而,它似乎起作用并不奇怪:对于一般情况下的varargs,在某些情况下传递int并将其作为unsigned int读取是有效的。 printf不是其中之一,但实施并不会阻止它看起来有效。