在C11匿名结构定义中使用宏

典型的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;
};

然后,我可以访问Base成员,因为它是Derived的一部分而没有任何演员或中间成员.如果需要,我可以将Derived指针强制转换为Base指针.

这可以接受吗?有任何陷阱吗?

最佳答案 有陷阱.

考虑:

#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甚至可能创建陷阱表示.

点赞