0

我有一个关于 C 的问题,并试图模拟部分类型的“继承”,仅在访问结构成员时。看下面的例子:

#pragma pack(push,1)
typedef struct foo
{
    int value;
    int value2;
}foo;
typedef struct foo_extended
{
    // "inherits" foo
    int value;
    int value2;
    // "inherits" foo stops
    //we also have some additional data
    float additional;
}foo_extended;
#pragma pack(pop)


//! This function works for both foo types
void workboth(void* objP)
{
    foo* obj = (foo*)objP;

    obj->value = 5;
    obj->value2 = 15;
}

//! This works only for the extended
void workextended(foo_extended* obj)
{
    obj->value = 25;
    obj->value2 = 35;
    obj->additional = 3.14;
}

int main()
{
    foo a;
    foo_extended b;

    workboth(&a);
    workboth(&b);
    workextended(&b);

    return 0;
}

这在我的系统中有效,但我的问题是,只要相关结构的正确打包(取决于编译器),这是否可以移植。我想它也需要#ifndefs 正确地调用其他编译器中的紧密打包。

当然,明显的问题是完全缺乏类型检查并将正确使用的所有责任交给程序员,但我想知道这是否可移植。谢谢!

PS:忘了说我尝试遵守的标准是C99

4

3 回答 3

1

我有一个稍微不同的方法。我没有使用相同的值,而是在结构中创建了一个结构,这样就不需要打包:

typedef struct foo
{
    int value;
    int value2;
}foo;

typedef struct foo_extended
{
    foo father;
    float additional;
}foo_extended;

现在剩下的和你展示的差不多,有一点不同:

void workextended(foo_extended* obj)
{
    obj->father.value = 25;
    obj->father.value2 = 35;
    obj->additional = 3.14;
}

但我会添加一个 id 作为层次结构中第一个对象的字段,以确保对正确的对象进行强制转换。

C 标准保证此方法有效。

于 2012-04-29T09:32:10.973 回答
1

struct从 C11 开始,一些现有编译器也支持作为旧标准的扩展,您应该为此使用匿名

struct foo_extended {
    struct {
      int value;
      int value2;
    };
    //we also have some additional data
    float additional;
};

这样,您的子结构具有完全相同的布局foo,特别是涉及其部分对齐的布局:为了struct在具有相同顺序的完全相同字段的不同编译单元之间兼容,必须以相同的方式布局。

(你打包的pragma的影响对我来说不是很清楚)

由于您的foo结构是第一个结构,foo_extended因此它必须始终在该结构中偏移0

于 2012-04-29T09:57:51.497 回答
0

通过阅读C99 草案中的 6.7.2.1/12 和 /13 ,我认为可以假设具有相同初始成员的两个不同结构与第一个不同成员兼容。

6.7.2.1/12

结构或联合对象的每个非位域成员都以适合其类型的实现定义的方式对齐。

6.7.2.1/13

在结构对象中,非位域成员和位域所在的单元的地址按声明顺序递增。一个指向结构对象的指针,经过适当的转换,指向它的初始成员(或者如果该成员是位域,则指向它所在的单元),反之亦然。结构对象中可能有未命名的填充,但不是在其开头。

于 2012-04-29T09:55:47.317 回答