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

时间:2014-11-10 10:20:05

标签: c macros struct coding-style c11

扩展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;
};

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

这可以接受吗?有没有陷阱?

1 个答案:

答案 0 :(得分:2)

存在陷阱。

考虑:

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