c - 在 C 中扩展结构

标签 c struct

我最近遇到了一位同事的代码,如下所示:

typedef struct A {
  int x;
}A;

typedef struct B {
  A a;
  int d;
}B;

void fn(){
  B *b;
  ((A*)b)->x = 10;
}

他的解释是,由于 struct Astruct B 的第一个成员,所以 b->xb->a.x 并提供更好的可读性。
这是有道理的,但这被认为是好的做法吗?这会跨平台工作吗?目前这在 GCC 上运行良好。

最佳答案

是的,它可以跨平台工作(a),但这不一定是个好主意。

根据 ISO C 标准(以下所有引用均来自 C11),6.7.2.1 Structure and union specifiers/15,不允许在之前进行填充结构的第一个元素

此外,6.2.7 兼容类型和复合类型指出:

Two types have compatible type if their types are the same

毫无疑问,AA-within-B 类型是相同的。

这意味着对 A 字段的内存访问在 AB 类型中将是相同的,更明智的是b->a.x 如果您对将来的可维护性有任何顾虑,这可能是您应该使用的。

而且,虽然您通常不得不担心严格的类型别名,但我认为这不适用于此处。别名指针是非法的,但标准有特定的异常(exception)。

6.5 Expressions/7 声明了其中一些异常(exception)情况,并附有脚注:

The intent of this list is to specify those circumstances in which an object may or may not be aliased.

列出的异常(exception)是:

  • 与对象的有效类型兼容的类型;
  • 其他一些我们在这里不必关心的异常(exception)情况;和
  • 在其成员中包含上述类型之一的聚合或 union 类型(递归地包括子聚合或包含的 union 的成员)

那,结合上面提到的struct padding规则,包括短语:

A pointer to a structure object, suitably converted, points to its initial member

似乎表明这个例子是特别允许的。这里我们要记住的核心点是表达式((A*)b)的类型是A*,不是B* .这使得变量兼容无限制的别名。

那是我对标准相关部分的解读,我在(b)之前就错了,但我对此表示怀疑。

因此,如果您有真正的需求,它可以正常工作,但我会在代码中非常记录与结构接近的任何约束,以便以免以后被咬。


(a) 一般意义上的。当然是代码片段:

B *b;
((A*)b)->x = 10;

将是未定义的行为,因为 b 没有被初始化为合理的东西。但我假设这只是用于说明您的问题的示例代码。如果有人担心它,请将其视为:

B b, *pb = &b;
((A*)pb)->x = 10;

(b) 正如我妻子会经常告诉你的那样 :-)

关于c - 在 C 中扩展结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22218604/

相关文章:

c - 在 DOS/FAT 中缩小或部分截断文件

c - 从 C 中的主函数返回与退出

c++ - 如何传递二维结构数组给函数?

c - 为什么修改数据字段会改变链接列表中的其他字段

c - 将结构数组传递给函数以输入值

c - C中的回文问题

c++ - 如何使用 C++ 在 Active Directory 的属性中设置值?

arrays - 包含结构数组的 MAT 文件的导入 [] - 仅导入第一个元素?

c - 使用结构体分配内存时出现段错误

c - realloc 是否在重新分配的字符串中包含\0?