是的。我们可以从大会得到答案。
这是我在 Ubuntu 16.04、64bit、gcc 中编写的示例。
#include <stdio.h>
typedef unsigned int uint32_t;
struct {
uint32_t foo1:8;
uint32_t foo2:24;
} G;
int main() {
G.foo1 = 0x12;
G.foo2 = 0xffffff; // G is 0xfffff12
printf("G.foo1=0x%02x, G.foo2=0x%06x, G=0x%08x\n", G.foo1, G.foo2, *(uint32_t *)&G);
G.foo2++; // G.foo2 overflow
printf("G.foo1=0x%02x, G.foo2=0x%06x, G=0x%08x\n", G.foo1, G.foo2, *(uint32_t *)&G);
G.foo1 += (0xff-0x12+1); // // G.foo1 overflow
printf("G.foo1=0x%02x, G.foo2=0x%06x, G=0x%08x\n", G.foo1, G.foo2, *(uint32_t *)&G);
return 0;
}
用gcc -S <.c file> 编译它。你可以得到汇编文件.s。这里我展示了G.foo2++;的汇编,我写了一些cmets。
movl G(%rip), %eax
shrl $8, %eax # 0xfffff12-->0x00ffffff
addl $1, %eax # 0x00ffffff+1=0x01000000
andl $16777215, %eax # 16777215=0xffffff, so eax still 0x01000000
sall $8, %eax # 0x01000000-->0x00000000
movl %eax, %edx # edx high-24bit is fool2
movl G(%rip), %eax # G.foo2, tmp123
movzbl %al, %eax # so eax=0x00000012
orl %edx, %eax # eax=0x00000012 | 0x00000000 = 0x00000012
movl %eax, G(%rip) # write to G
我们可以看到编译器会使用移位指令来保证你说的话。(注意:这里的G的内存布局是:
----------------------------------
| foo2-24bit | foo1-8bit |
----------------------------------
当然,前面的结果是:
G.foo1=0x12, G.foo2=0xffffff, G=0xffffff12
G.foo1=0x12, G.foo2=0x000000, G=0x00000012
G.foo1=0x00, G.foo2=0x000000, G=0x00000000