Pas*_*uoq 17 c c99 sequence-points bit-fields c11
对于打包f0
并f1
放入同一字节的实现,下面的程序是定义的吗?
struct S0 {
unsigned f0:4;
signed f1:4;
} l_62;
int main (void) {
(l_62.f0 = 0) + (l_62.f1 = 0);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我对C99和C11的答案感兴趣,如果有理由认为它在那里是不同的.
在C99中,我发现的只有6.5:2:
在前一个和下一个序列点之间,一个对象的存储值最多只能通过表达式的评估来修改一次.[...]
我不清楚这一段对上述计划有何影响.
基于大量随机测试,大多数编译器似乎生成代码,其中两个分配不会干扰.
C11 认为相邻的命名位字段是同一内存位置的一部分。此类位字段不保证以原子方式更新,换句话说,如果一个更新未在另一个更新之前显式排序,则行为未定义。3.14 memory location
然后还详细解释了何时可以认为两个字段位于不同的内存位置,因此可以独立考虑对它们的更新。
如果你想修改你的结构
struct S0 {
unsigned f0:4;
int :0;
signed f1:4;
} l_62;
Run Code Online (Sandbox Code Playgroud)
这样,两个位字段之间就有这个奇怪的“内存位置分隔符”,您的代码就可以保证没问题。
对于C99来说情况似乎更复杂,没有这么详细的内存位置概念。在最近关于 Linux 内核邮件列表的讨论中,有人声称,通常对于所有位字段对,在更新其中任何一个位字段时都会保证原子性。该讨论的出发点是 gcc 以意想不到的方式污染了与位字段相邻的非位字段,从而导致虚假崩溃。