位域溢出
我可以相信每次访问位字段时 C 编译器都会对 2^n 取模吗? 或者是否有任何编译器/优化,其中像下面这样的代码不会打印出溢出?
struct {
uint8_t foo:2;
} G;
G.foo = 3;
G.foo++;
if(G.foo == 0) {
printf("Overflow\n");
}
提前致谢,弗洛里安
can I trust that the C compiler does modulo 2^n each time I access a bit field?
Or is there any compiler/optimisation where a code like the one below would not print out Overflow?
struct {
uint8_t foo:2;
} G;
G.foo = 3;
G.foo++;
if(G.foo == 0) {
printf("Overflow\n");
}
Thanks in Advance, Florian
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
是的,您可以相信 C 编译器会在此处执行正确的操作,只要使用
uint8_t
所具有的无符号类型声明位字段即可。来自 C99 标准 §6.2.6.1/3:从 §6.7.2.1/9 开始:
从§6.2.5/9(强调我的):
所以是的,您可以确保任何符合标准的编译器都会将
G.foo
溢出到 0,而不会产生任何其他不需要的副作用。Yes, you can trust the C compiler to do the right thing here, as long as the bit field is declared with an unsigned type, which you have with
uint8_t
. From the C99 standard §6.2.6.1/3:From §6.7.2.1/9:
And from §6.2.5/9 (emphasis mine):
So yes, you can be sure that any standards-conforming compiler will have
G.foo
overflow to 0 without any other unwanted side effects.不会。编译器为该字段分配 2 位,递增 3 会得到 100b,而放入 2 位时会得到 0。
No. The compiler allocates 2 bits to the field, and incrementing 3 results in 100b, which when placed in two bits results in 0.
是的。我们可以从汇编中得到答案。
这是我在 Ubuntu 16.04、64 位、gcc 中编写的示例。
使用
gcc -S <.c file>
编译它。您可以获取汇编文件.s
。这里我展示了G.foo2++;
的汇编,并写了一些注释。我们可以看到,编译器会使用移位指令来确保你所说的。(注:这里G的内存布局是:
当然,前面提到的结果是:
Yes. We can get the answer from assembly.
Here is a example I code in Ubuntu 16.04, 64bit, gcc.
Compile it with
gcc -S <.c file>
. You can get the assembly file.s
. Here I show the assembly ofG.foo2++;
, and I write some comments.We can see that compiler will use shift instructions to ensure what you say.(note: here's memory layout of G is:
Of course, the result of aforementioned is:
简短的回答:是的,您可以相信模 2^n 会发生。
在你的程序中,
G.foo++;
实际上相当于G.foo = (unsigned int)G.foo + 1
。无符号整型算术总是产生 2^(无符号整型的大小(以位为单位))结果。然后,权重最小的两位存储在 G.foo 中,产生零。
Short answer: yes, you can trust modulo 2^n to happen.
In your program,
G.foo++;
is in fact equivalent toG.foo = (unsigned int)G.foo + 1
.Unsigned int arithmetic always produces 2^(size of unsigned int in bits) results. The two bits of least weight are then stored in
G.foo
, producing zero.