C/C++结构体不完整成员类型为何有差异?指针成员为何合法?
为什么结构体中包含不完整类型的指针成员能编译,而值成员不行?
这个问题问到了C和C++类型系统里一个很关键的点——不完整类型的使用限制。咱们一步步来理清楚:
1. 为什么值成员版本会报错?
当你写这段代码时:
struct abc{ int data; struct nonexsitnow next; // 编译报错:field ‘next’ has incomplete type };
编译器需要确定struct abc的总大小和内存布局,这就要求它知道每个成员的具体大小。但struct nonexsitnow既没有被声明过,也没有被定义过,属于完全未知的类型,编译器根本不知道它占多少字节,自然没法给struct abc分配合适的内存空间,所以这个报错完全合理。
2. 为什么指针成员版本能正常编译?
再看这段代码:
struct abc{ int data; struct nonexsitnow *next; // 编译通过 };
这里的核心是:指针的大小是固定的,和它指向的类型无关。不管struct nonexsitnow是什么样的结构体,在当前平台下(比如32位系统是4字节,64位是8字节),指针的大小都是编译器已知的。所以编译器不需要知道struct nonexsitnow的具体定义,就能确定struct abc的内存布局——只需要给next留一个指针大小的空间就行。
另外这里还涉及到C和C的隐式声明规则:当你使用struct nonexsitnow但之前没有任何声明时,C会自动隐式声明一个不完整类型struct nonexsitnow;,C也有类似的行为(不过两者在后续使用上有细微差异)。而指针指向不完整类型是完全合法的,只要你后续在需要解引用这个指针之前,补全struct nonexsitnow的定义就行。
补充:C和C++对不同声明/定义状态下类型使用的差异
结合社区讨论,咱们可以用一张表格清晰对比C和C++在不同场景下的行为:
| 未声明类型 | 已声明未定义(不完整类型) | 已定义类型 | ||||
|---|---|---|---|---|---|---|
| C | C++ | C | C++ | C | C++ | |
| ---------------- | -------------- | ---------- | -------------- | ---------- | ---------- | ---------- |
struct Foo p; | ❌ 编译错误 | ❌ 编译错误 | ❌ 编译错误 | ❌ 编译错误 | ✅ 正常通过 | ✅ 正常通过 |
struct Foo* p; | ✅ 正常通过 | ✅ 正常通过 | ✅ 正常通过 | ✅ 正常通过 | ✅ 正常通过 | ✅ 正常通过 |
Foo p; | ❌ 编译错误 | ❌ 编译错误 | ❌ 编译错误 | ❌ 编译错误 | ❌ 编译错误(C中无此写法) | ✅ 正常通过 |
Foo* p; | ❌ 编译错误 | ❌ 编译错误 | ❌ 编译错误 | ✅ 正常通过 | ❌ 编译错误(C中无此写法) | ✅ 正常通过 |
简单解释下表格的关键点:
- 在C中,必须写
struct Foo来引用结构体类型,直接写Foo是不合法的;而C++中,struct Foo定义后可以直接用Foo指代。 - 不管是C还是C++,指针指向不完整类型都是允许的,但直接声明不完整类型的实例(值成员)是不允许的,因为编译器无法确定其大小。
内容的提问来源于stack exchange,提问作者alandawkins
相关产品推荐
相关产品推荐

