繁体   English   中英

位域和序列点

[英]Bit-fields and sequence points

对于将f0f1打包到同一个字节的实现,下面的程序是否已定义?

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:

在前一个和下一个序列点之间,一个对象的存储值最多只能通过表达式的评估来修改一次。 [...]

我不清楚这一段对上述计划有何影响。

基于大量随机测试,大多数编译器似乎生成代码,其中两个分配不会干扰。

C11认为相邻的命名位字段是同一存储器位置的一部分。 这些位字段不能保证以原子方式更新,换句话说,如果一个更新未在另一个之前显式排序,则行为未定义。 3.14 memory location然后还详细说明何时可以认为两个字段位于不同的存储器位置,因此可以独立地考虑对它们的更新。

如果你要修改你的结构

struct S0 {
       unsigned f0:4;
       int :0;
       signed f1:4;
} l_62;

这样两个位字段之间就有这个奇怪的“内存位置分隔符”,您的代码将保证正常。

对于C99来说,情况似乎更复杂,没有这么详细的内存位置概念。 在最近关于linux内核邮件列表的讨论中,有一种说法,即通常对于所有位字段对,在更新任何位字段时都会保证原子性。 该讨论的起点是gcc以意想不到的方式污染了与位字段相邻的非位字段导致虚假崩溃的情况。

这里的赋值是结构成员。 他们碰巧共享相同存储的事实应该对逻辑没有影响。 事实上,你实际上并没有对同一件事做出任务。

当然,我不是语言律师。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM