受到question的启发,我有:
#include<stdio.h>
struct st
{
int a:1;
int b:2;
};
int main()
{
struct st obj={1, 2};
printf("a = %d\nb = %d\n",obj.a,obj.b);
}
我得到了:
Georgioss-MacBook-Pro:~ gsamaras$ gcc -Wall main.c
main.c:10:26: warning: implicit truncation from 'int' to bitfield changes value
from 2 to -2 [-Wbitfield-constant-conversion]
struct st obj={1, 2};
^
1 warning generated.
Georgioss-MacBook-Pro:~ gsamaras$ ./a.out
a = -1
b = -2
我想我理解为什么两个位域都不能保持它们的值(按照answer),但我不明白为什么编译器只警告2
,而不是{{ 1}}!有什么想法吗?
我在Mac上使用:
1
在一个旧的Linux系统中,使用gcc版本4.6.3(Ubuntu / Linaro 4.6.3-1ubuntu5),我没有收到任何相关的警告。
在Debian安装中,使用gcc版本4.9.2(Debian 4.9.2-10),我没有收到任何相关警告!
答案 0 :(得分:1)
https://en.wikipedia.org/wiki/Two%27s_complement
可能会发生一些事情,也许一些实验可能有所帮助。
首先,可能是gcc足够聪明,知道单个位实际上不能为正或负,因为它只是单个位。
另一种可能性是gcc评估表达式的顺序与你的想法相反。一些编译器从右到左进行评估,在您的情况下,将错误踢出并停止。
要进行测试,请更正b的位域以保持有符号整数为“2”而不翻转符号位(3位应该有效)。如果在修复'b'时你已经为'a'生成了错误,那么你知道它只是编译器评估顺序。
如果修复'b'不会导致'a'发出警告,那么gcc会对单个位字段执行一些内部优化。
此外,将您的位域类型更改为'uint'也应该修复警告,在这种情况下,它只是表示的标志位被翻转。
快乐的编码。
修改强> 相关源代码:https://github.com/llvm-mirror/clang/blob/master/lib/Sema/SemaChecking.cpp#L8812
答案 1 :(得分:0)
int b:2;
是2位宽的有符号整数。数字2(无符号)在二进制文件中表示为10
,因为source int是有符号的,所以实际上您将已签名的数字保存到内存中。
这就是你收到此警告的原因。
您可以保存为2位signed int的值为:(-2 = 11, -1 = 10, 0 = 00, 1 = 01)
两种情况下你没有得到的原因是int a:1
只有1位且可以保留数字1
或0
,而没有负数。