对于将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;
}
我对C99和C11的答案感兴趣,如果有理由认为它在那里有所不同。
在C99中,我发现的只有6.5:2:
在前一个和下一个序列点之间,一个对象应该具有它 储值通过表达式的评估最多修改一次。 [...]
我不清楚这一段对上述计划有何影响。
基于大量随机测试,大多数编译器似乎生成代码,其中两个分配不会干扰。
答案 0 :(得分:3)
C11认为相邻的命名的位字段是同一内存位置的一部分。这些位字段不能保证以原子方式更新,换句话说,如果一个更新未在另一个之前显式排序,则行为未定义。 3.14 memory location
然后还详细解释了何时可以认为两个字段位于不同的内存位置,因此可以单独考虑对它们的更新。
如果要修改结构
struct S0 {
unsigned f0:4;
int :0;
signed f1:4;
} l_62;
这样两个位字段之间存在这个奇怪的“存储位置分隔符”,您的代码将保证正常。
对于C99来说,情况似乎更复杂,没有这么详细的内存位置概念。在最近关于linux内核邮件列表的讨论中,有一种说法,即通常对于所有位字段对,在更新任何位字段时都会保证原子性。该讨论的起点是gcc以意想不到的方式污染了与位字段相邻的非位字段导致虚假崩溃的情况。
答案 1 :(得分:0)
这里的赋值是结构成员。他们碰巧共享相同存储的事实应该对逻辑没有影响。事实上,你实际上并没有对同一件事做出任务。
当然,我不是语言律师。