内存中结构布局的定义有多好?

时间:2014-06-11 06:52:44

标签: c struct padding

当我看到它们时,有很多C语言(作为一个主要的C ++程序员)让我的皮肤爬行。

成语1

struct A
{
    int id;
    int bar;
    char *quux;
};

struct B
{
    int id;
    double foo1;
    double foo2;
};

struct C
{
    int id;
    void *something;
};

union X
{
    int id;
    struct A a;
    struct B b;
    struct C c;
};

union X x;

我看到这样做,例如,GTK +,它以这种方式处理事件。有一组结构,每个结构包含有关特定事件类型的信息,每个结构都以int id开头,与X.id对齐,以便可以用来确定联合中的结构类型实际初始化。

成语2

struct A
{
    int count;
};

struct B
{
    struct A a;
    void *foo;
    float bar;
};

struct X
{
    struct B b;
    int wibble;
    int wobble;
    int wubble;
    int flob;
};

struct X *x = make_X(); // malloc me an X and initialize it

我看到这个习惯用于C对象的主动引用计数。让我害怕的成语的特定部分是这样的部分,为了获得引用计数数据,我们的struct X*直接转换为struct A*,它依赖于在没有填充的情况下创建的结构,以及它们的元素按照定义中指定的顺序。

问题

这些习语是否在C中得到了很好的定义?总是,永远,永远不会?经验证据表明它们会在某些情况下起作用,但我不知道它们是否正在工作,因为它们被定义为可行,或者它们是否依赖于某种未定义的行为。 GTK依赖其中一个这一事实并没有让我更愿意相信它的定义很好,这不是linux家伙第一次依赖平台特定的行为。我非常感谢标准相关部分的一些链接,但我不确定从哪里开始寻找。

2 个答案:

答案 0 :(得分:3)

C11 6.7.2.1结构和联合说明符p15表示

  

在结构对象中,非位字段成员和单位   哪些位字段驻留的地址按顺序增加   他们被宣布。 适当地指向结构对象的指针   已转换,指向其初始成员(或者如果该成员是   位字段,然后到它所在的单元,反之亦然。   结构对象中可能有未命名的填充,但不在其中   开始。

因此可以安全地假设x在您的示例中指向x->b.a.count

答案 1 :(得分:2)

C标准规定在结构的第一个成员之前可能没有填充。