警告只有一个位域,而不是两个?

Warning about only one bitfield, instead of both?

受此启发,我有:

#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 中使用:

Georgioss-MacBook-Pro:~ gsamaras$ gcc -v
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 8.1.0 (clang-802.0.38)
Target: x86_64-apple-darwin16.3.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

在旧的 Linux 系统中,gcc 版本 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5),我没有收到相关警告。

在 Debian 安装中,gcc 版本 4.9.2 (Debian 4.9.2-10),我没有收到相关警告!

int b:2; 是 2 位宽的有符号整数。数字 2(无符号)在二进制中表示为 10,并且因为源 int 是有符号的,所以您实际上将带符号的数字保存到内存中。

这就是您收到此警告的原因。

可以保存为 2 位有符号整数的值是:(-2 = 11, -1 = 10, 0 = 00, 1 = 01)

你在这两种情况下都没有得到的原因是 int a:1 只有 1 位并且可以容纳数字 10,没有负数。

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