You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 04:25:16