在C语言中,指向结构体的指针是否总是指向它的第一个成员?

36

假设我有一些C结构体,我想要特定一组函数对它们进行操作。

我想知道以下是否是一个合法的方法:

typedef struct Base {
     int exampleMember;
     // ...
} Base;

typedef struct Foo {
     Base base;
     // ...
} Foo;

typedef struct Bar {
     Base base;
     // ...
} Bar;

void MethodOperatesOnBase(void *);

void MethodOperatesOnBase(void * obj)
{
     Base * base = obj;
     base->exampleMember++;
}
在示例中,您会注意到两个结构体FooBar都以一个Base成员开头。
而且,在MethodOperatesOnBase中,我将void*参数转换为Base*
我想将指向Bar和指向Foo的指针传递给此方法,并依赖于结构体的第一个成员是Base结构体。
这样做是否可行,或者是否存在一些(可能是特定于编译器的)问题需要我注意?(例如某种打包/填充方案会更改结构体第一个成员的位置等)?

2
你为什么不直接使用C++呢? - Jonathan Grynspan
2
我理解你的意思,但是对于这个项目来说我做不到。 - Steve
1
这是作业吗?我已经毕业十年了,但还是谢谢。哈哈 - Steve
4
@Jonathan Grynspan提出了一个合理的问题。假设你的程序有10,000行,用C语言编写。那么你大约需要100行代码进行结构体截断。在这种情况下,为了使整个程序与C语言兼容,花费更多的努力是值得的。请注意保持原文意思,使翻译通俗易懂。 - Mysticial
把标题修改为更具描述性(而且更容易在谷歌搜索到)的内容,如果您不介意的话。 - Alexandre C.
显示剩余6条评论
3个回答

41

是的,C标准明确保证这将起作用。

(C1x §6.7.2.1.13: “指向结构体对象的指针,在适当转换后,指向其第一个成员……反之亦然。在结构体对象内可能存在未命名填充位,但不会在其开头处出现。”)


@MByD:标准本身由于愚蠢的版权原因无法链接,但是谷歌可以为您找到几份草案。 - hmakholm left over Monica
在委员会草案中的6.7.2.1.15:C11标准可以在此处找到:http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf。 - Eric Hou

2

1

我不反对任何回答中提到的你所建议的方法,但为了更全面地讨论(并且不建议你使用C++!),为什么不尝试做一些类似于以下的事情

typedef struct Base ...  /* The types defined exactly as before */
typedef struct Foo ...
typedef struct Bar ...

/* The function takes a Base* since that is what it actually works with*/
void MethodOperatesOnBase(Base* pbase)
{
    /* Do something... */
}

/* Now call it like this: */
Foo foo;
Bar bar;

MethodOperatesOnBase(&foo.base);
MethodOperatesOnBase(&bar.base);

有什么原因不能使用 void * 吗?我认为这并不会增加太多工作量,而且它具有类型安全的优点。


嗯,在我的情况下,原因是因为FooBar被公开作为不透明指针。 - Steve
1
@ Steve:好的,所以调用者无法引用 base 成员,你必须通过重新解释结构指针来完成。这很有道理,谢谢你澄清。 - AAT

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接