【问题标题】:Using macro in C11 anonymous struct definition在 C11 匿名结构定义中使用宏
【发布时间】:2014-11-10 10:20:05
【问题描述】:

扩展 stuct 的典型 C99 方式类似于

struct Base {
    int x;
    /* ... */
};

struct Derived {
    struct Base base_part;
    int y;
    /* ... */
};

然后我们可以将struct Derived *的实例转换为struct Base *,然后访问x

我想直接访问struct Derived * obj; 的基本元素,例如obj->x 和obj->y。 C11 提供扩展结构,但正如 here 所解释的,我们只能将此功能与匿名定义一起使用。那怎么写呢

#define BASE_BODY { \
    int x; \
}

struct Base BASE_BODY;

struct Derived {
    struct BASE_BODY;
    int y;
};

然后我可以访问与 Derived 的一部分相同的 Base 成员,而无需任何强制转换或中间成员。如果需要,我可以将 Derived 指针转换为 Base 指针。

这可以接受吗?有什么陷阱吗?

【问题讨论】:

  • 作为替代方案,您可以考虑通过gccclang 中的-fms-extensions 选项使用typedef(请参阅this 答案),但它是非标准的。

标签: c macros struct coding-style c11


【解决方案1】:

有陷阱。

考虑:

#define BASE_BODY { \
    double a; \
    short b; \
}

struct Base BASE_BODY;

struct Derived {
    struct BASE_BODY;
    short c;
};

在某些实现上可能是sizeof(Base) == sizeof(Derived),但是:

struct Base {
    double a;
    // Padding here
    short b;
}

struct Derived {
    double a;
    short b;
    short c;
};

不保证结构体开头的内存布局是一样的。因此,您不能将这种Derived * 传递给期望Base * 的函数,并期望它能够工作。

即使填充不会弄乱布局,仍然存在陷阱呈现的潜在问题:

如果再次sizeof(Base) == sizeof(Derived),但c 最终到达Base 末尾处的填充覆盖的区域。将此结构的指针传递给需要 Base* 并对其进行修改的函数,可能也会影响填充位(填充具有未指定的值),因此可能会破坏 c,甚至可能创建陷阱表示。

【讨论】:

  • 这是真的。我在结构定义和向上转换的可怕损坏结果之前放置了不同的#pragma 包。
猜你喜欢
  • 2018-03-28
  • 2018-01-27
  • 2023-03-04
  • 1970-01-01
  • 2012-02-14
  • 1970-01-01
  • 2018-02-08
  • 2018-01-05
  • 1970-01-01
相关资源
最近更新 更多