【问题标题】:Warning about only one bitfield, instead of both?警告只有一个位域,而不是两个?
【发布时间】:2017-05-10 11:15:32
【问题描述】:

受到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 上使用:

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

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

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

【问题讨论】:

  • fyi g++ 5.1.0 按预期产生 2 个警告。 2 * warning: overflow in implicit constant conversion [-Woverflow]

标签: c struct compilation warnings bit-fields


【解决方案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

【讨论】:

  • 当我修复 b 时,我根本没有收到 a 的警告。 . .但是 +1 的想法!
  • 酷。我可能会把钱花在专门针对单个案例的 gcc 上。在 C++ 中,这是使用部分模板特化完成的,我认为 gcc 是用 C++ 编写的。
  • 我在这里找到了clang的源代码检查:github.com/llvm-mirror/clang/blob/master/lib/Sema/…
【解决方案2】:

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

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

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

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

【讨论】:

  • 感谢您的回答,但问题是为什么我没有收到两个警告! :)
  • 但如果是这样的话,我希望 1 被打印出来。请参阅最初的链接问题以获取更多信息。
猜你喜欢
  • 2019-08-02
  • 2012-11-05
  • 2017-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-04
  • 1970-01-01
相关资源
最近更新 更多