【问题标题】:Mixing bitfields in structures在结构中混合位域
【发布时间】:2016-02-15 10:28:25
【问题描述】:

挂在geeksforgeeks上关于位域,找到了这个例子:

#include <stdio.h>

struct test {
    unsigned int x;
    long int y : 33;
    unsigned int z;
};

int main() {
    struct test t;
    unsigned int *ptr1 = &t.x;
    unsigned int *ptr2 = &t.z;
    printf("%d", ptr2 - ptr1);
    return 0;
}

结果,输出为 4。但为什么呢? x占4个字节,y-8,z-4。x和z的地址差一定是8?

【问题讨论】:

  • 两个指针之间的差异不以字节为单位,而是以指针指向的任何类型。此外,type 与最对齐成员的对齐方式(可能是long int)和&amp;test.x == &amp;test 对齐,所以如果sizeof(unsigned) != sizeof(long int)test.xtest.y 之间存在对齐间隙(填充),如果实现甚至接受long int 类型的位域。
  • 我在每篇文章中不断听到这个“geekforgeeks”,其中包含糟糕的、指定不当的行为、无意义的代码。我真的认为你应该避开那个网站,他们似乎不太了解他们在说什么。
  • Lundin:也许我可以同意,我几天前才发现它……但无论如何,这个棘手的“真空中的球形马”示例让我很苦恼:)
  • @artsin 正确的说法是球形牛。
  • @artsin 代码是球马写的?从这段代码中唯一可以学到的是应该完全避免位域。以See this 为例。

标签: c bit-fields


【解决方案1】:

此代码没有可确定的行为。如果没有一个非常具体的编译器,就不可能预测它的任何结果。

它包含以下实现定义的行为(引自标准附件 J):

——“plain”int 位域是否被视为带符号的 int 位域或作为无符号整数位域(6.7.2、6.7.2.1)。

- _Bool、signed int 和 unsigned 以外的允许位域类型 整数(6.7.2.1)。

— 位域是否可以跨越存储单元边界 (6.7.2.1)。

——一个单元中位域的分配顺序(6.7.2.1)。

——结构的非位域成员的对齐 (6.7.2.1)。这 应该没有问题,除非二进制数据由一个写入 实现被另一个人读取。

第二句话也暗示编译器必须有一个非标准的扩展。

除此之外,代码还取决于字节顺序,您无法知道位域中的哪些位是 MSB 和 LSB。

【讨论】:

  • 更多相关:C11 标准草案6.5.6 Additive operators, Section 9 When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object;[...]。尽管6.5.8 Relational operators, Section 5 [...] If the objects pointed to are members of the same aggregate object, pointers to structure members declared later compare greater than pointers to members declared earlier in the structure[...] 使得它很可能没有真正的实现会使这段代码失败。
  • 另外,sizeof(int)sizeof(long) 也是实现定义的。我们可以在这里看到这段代码是使用 64 位非 MSVC 编译器编译的,因为 sizeof(long) 是 8。对于 MSVC 或 32 位编译器,sizeof(long) 是 4。
  • @EOF 是的,我确信有人可以写一篇完整的文章来说明这段代码可能/将如何出错。就是不要写这种无意义的代码,不会有问题的。
猜你喜欢
  • 1970-01-01
  • 2020-09-01
  • 2011-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多