C语言头文件中extern与普通结构体声明的用法疑问
嵌入式C中匿名结构体全局变量的声明/定义疑问解答
头文件structures.h代码:
#ifdef _structures_h_ extern struct{ uint16_t State_ON; uint16_t State_OFF; uint16_t State_HI; uint16_t Counter; }Switch; #endif #ifndef _structures_h_ #define _structures_h_ struct{ uint16_t State_ON; uint16_t State_OFF; uint16_t State_HI; uint16_t Counter; }Switch; #endif
两种头文件包含方式:
- 定义变量的源文件:
#include "structures.h"
- 使用变量的其他源文件:
#define _structures_h_ #include "structures.h"
1. 为何同一个头文件采用两种声明方式?
这是一种把全局变量的定义和声明逻辑整合到单个头文件的技巧,核心目的是避免链接阶段的多重定义错误:
- 当源文件直接包含头文件时,
_structures_h_未被定义,会触发#ifndef分支——这里是Switch的唯一定义点,编译器会为这个全局变量分配内存,项目中应该只有一个源文件这么做。 - 当源文件先定义
_structures_h_再包含头文件时,会触发#ifdef分支——这里只是Switch的声明,告诉编译器这个变量在其他编译单元已经存在,当前文件可以直接使用,不会分配内存。
这种写法省去了拆分声明和定义到不同文件的麻烦,用宏开关控制同一个头文件输出定义或声明。
2. 加extern与不加extern的差异
本质是变量定义和变量声明的区别:
- 不加
extern:属于全局变量定义,编译器会为Switch分配内存,全局变量默认被初始化为0。如果多个源文件都执行这个分支,链接时会报multiple definition错误,因为全局变量不能重复定义。 - 加
extern:属于全局变量声明,仅向编译器告知“存在一个名为Switch的全局变量,类型是这个匿名结构体”,不会分配内存。它的作用是让当前编译单元可以引用其他地方定义的Switch,前提是声明的结构体类型和定义的完全一致(这里两个结构体的成员类型、顺序、数量都相同,所以可以正常匹配)。
额外注意:因为用的是匿名结构体,声明和定义的结构体必须完全一致,否则会出现类型不匹配的未定义行为。
内容的提问来源于stack exchange,提问作者Geisterfahrer
相关产品推荐
相关产品推荐

