17

对于打包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:

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

我不清楚这一段对上述程序有什么影响。

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

4

2 回答 2

3

C11 将相邻的命名位字段视为同一内存位置的一部分。不能保证这样的位字段会自动更新,换句话说,如果一个更新没有在另一个更新之前明确排序,则行为是未定义的。3.14 memory locationthen 还详细解释了何时可以认为两个字段位于不同的内存位置,因此可以独立考虑对它们的更新。

如果你要修改你的结构

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

这样两个位字段之间就有这个奇怪的“内存位置分隔符”,你的代码就可以保证没问题。

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

于 2012-02-05T20:43:45.310 回答
0

这里的分配是给结构成员的。他们碰巧共享相同存储的事实应该对逻辑没有影响。事实上,你实际上并没有对同一件事进行分配。

当然,我不是语言律师。

于 2012-02-05T20:03:55.033 回答