对于将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:
在前一个序列点和下一个序列点之间,对象的存储值最多应该通过表达式的求值
fi一次。..。
对我来说,这段话对上面的程序有什么影响还不清楚。
根据大量的随机化测试,大多数编译器似乎都会生成两个赋值不干扰的代码。
发布于 2012-02-06 04:43:45
C11将相邻的命名位字段视为同一内存位置的一部分。这样的位字段不能保证自动更新,换句话说,如果一个更新没有在另一个更新之前显式地排序,则行为是未定义的。然后,3.14 memory location
还详细解释了何时可以认为两个字段位于不同的内存位置,因此可以独立考虑对它们的更新。
如果你想修改你的结构
struct S0 {
unsigned f0:4;
int :0;
signed f1:4;
} l_62;
这样,在两个位字段之间有一个奇怪的“内存位置分隔符”,您的代码就可以保证是正确的。
对于C99来说,情况似乎更复杂,没有关于内存位置的详细概念。在最近关于linux内核邮件列表的一次讨论中,有一种说法是,通常对于所有位字段对,当更新其中任何一个字段时,都会保证原子性。讨论的起点是一个案例,在这个案例中,gcc以一种意想不到的方式污染了与位域相邻的非位域,导致了虚假崩溃。
发布于 2012-02-06 04:03:55
这里的赋值是给结构成员的。它们恰好共享相同的存储,这一事实不应该对逻辑产生影响。实际上,你并没有给同样的东西赋值。
当然,我不是语言律师。
https://stackoverflow.com/questions/9151608
复制相似问题