C语言typedef与结构体声明顺序为何导致编译差异
C语言两段代码编译差异的核心原因
编译结果现象
- 第一段代码可正常通过编译
- 第二段代码编译时抛出明确错误:
error: unknown type name ‘api_set’、error: unknown type name ‘api_read’
可正常编译的代码片段
typedef struct _api_t api_t; typedef void (*api_set) (api_t * api; int a; ); typedef int (*api_read) (api_t * api; ); struct _api_t { api_set set; api_read read; };
编译报错的代码片段
typedef struct _api_t { api_set set; api_read read; } api_t; typedef void (*api_set) (api_t * api; int a; ); typedef int (*api_read) (api_t * api; );
底层原理
C语言采用单遍顺序扫描的编译逻辑,所有自定义类型、变量、函数都必须遵循先声明、后使用的强制规则,编译器不会提前扫描后续代码来识别还没声明的标识符。两段代码的唯一本质差异就是类型声明的先后顺序:
- 第一段代码的声明顺序完全符合规则:
- 第一行先做结构体前置声明:
typedef struct _api_t api_t;,这一步先让编译器知道api_t是对应struct _api_t的类型别名。因为后续api_set、api_read里只用了api_t*(指针类型,编译器不需要知道结构体的具体内存布局,只要识别到这是个指向对应结构体的指针即可),这个不完整类型的前置声明完全合法。 - 紧接着顺序定义
api_set、api_read两个函数指针类型别名,这一步用到的api_t*已经完成前置声明,编译器可以正常识别。 - 最后定义
struct _api_t的完整结构体内容时,成员用到的api_set、api_read类型已经完成声明,编译器可以正确解析成员类型,因此编译通过。
- 第一行先做结构体前置声明:
- 第二段代码的声明顺序违反了先声明后使用的规则:
- 代码一上来就定义
struct _api_t的完整结构,写成员set、read的类型时,api_set、api_read两个类型别名的typedef定义还写在结构体定义的后面。编译器顺序扫描到这两个成员的时候,还没读到后续的类型定义,根本识别不了api_set、api_read是什么,直接抛出未知类型错误。
- 代码一上来就定义
注:示例代码里函数指针参数列表用分号分隔是GCC支持的老式非标准语法,和本次的类型报错没有关联,不影响上述顺序规则的判定。
内容的提问来源于stack exchange,提问作者Wojciech Mierzejewski
相关产品推荐
相关产品推荐

