2

我想在 C 中的结构中添加一个字段。例如,我有以下结构。

struct A
{
 some_type x;
 some_type y;
}

我声明了一个新结构,就像这样。

struct B
{
 A a;
 some_type z;
}

现在说我有这样的功能。

int some_function( A * a )

是否可以在程序中像这样将 B 类型的变量传递给它。

B * b;
......
A * a = (A*)b;
some_function( a );

并且还可以some_function通过使用a->x例如使用里面的字段?

4

5 回答 5

9

是的,它是有效的。标准词,C99 6.7.2.1/13:

...指向结构对象的指针,经过适当转换,指向其初始成员(或者如果该成员是位域,则指向它所在的单元),反之亦然。结构对象中可能有未命名的填充,但不是在其开头。

于 2012-06-03T16:55:38.430 回答
1

是的,它会工作。A a 将是结构中的第一个成员

这就是一些人在 C 中模拟 OO 继承的方式

您可以使用

  &b->a

而不是演员。并且可能会做一个 ASSERT 之类的

 ASSERT (&b->a == b)

当你不小心破坏了这个语义时被警告

于 2012-06-03T16:49:58.043 回答
1

为什么不直接调用成员的方法呢?

some_function( &b->a );

您的代码现在可以工作了,但是如果有人决定更改 的成员B怎么办?还是之前添加了新成员a

于 2012-06-03T16:52:40.333 回答
0

不,它不会工作。如果你稍微改变一下它会起作用:

struct A
{
 some_type x;
 some_type y;
}; /* <- note semicolon here */


struct B
{
 struct A a;
 some_type z;
}; /* ... and here */


int some_function(struct A *a ); /* ... and here ... */


struct B *b;
......
struct A *a = (struct A*)b;
some_function( a );
于 2012-06-03T16:59:24.263 回答
0

是的,这会起作用,但只是偶然。

如果我正确地记得 C99 标准,那么这个特殊情况特别需要按您的预期工作。但很明显,这只是因为在此之前有足够多的人依赖它工作,并且它确实在足够多的实现中偶然工作,C99 标准委员会才觉得有义务为其在法律上和事实上的工作进行立法。

不要让这诱使您认为这是一个好主意。

任何依赖于标准边缘案例的东西都永远在崩溃的边缘摇摇欲坠,因为它看起来很老套(这会让你的代码的未来读者感到不舒服)并且看起来很聪明(这让他们对更改/修复任何东西感到紧张)。它还引导人们做出假设,因为您已经处于合法的边缘,可能会诱使人们越过边界进入损坏的代码。例如,结构中的第一个子结构中的第一个元素按照您的预期对齐,这并不意味着任何其他子元素都对齐。它适用于您的编译器这一事实并不意味着它适用于其他任何人的编译器,从而导致令人费解的令人困惑的错误。

写:

A *a = &(b->a);

(正如上面的评论所暗示的),你的意思很清楚。

如果出于某种晦涩的原因您必须强制B*转换为A*,那么请写一个非常清晰的评论,解释为什么您别无选择,只能做您必须做的事情,向读者保证它是合法的,并指出 C99 标准的小节许可它。

如果你真的找不到那个小节(并且发现它是你的家庭作业/忏悔),那么评论一下,我会挖掘它。

于 2012-06-03T17:14:36.160 回答