全局变量为什么通常在 .c 中定义、在头文件中 extern 声明?
定义为对象分配存储,声明只告诉编译器名称与类型。若头文件直接放普通外部链接定义,被多个翻译单元包含后会产生多重定义或依赖历史暂定定义行为;常见做法是一处定义、头文件 extern 声明。
Question Bank
按知识、方向与难度筛选;每道题都有分层回答和工程追问。
定义为对象分配存储,声明只告诉编译器名称与类型。若头文件直接放普通外部链接定义,被多个翻译单元包含后会产生多重定义或依赖历史暂定定义行为;常见做法是一处定义、头文件 extern 声明。
对齐要求决定对象合法起始地址,编译器会在成员之间和结构体尾部插入填充。某些内核能处理非对齐访问但性能下降,另一些会直接产生总线异常;协议数据应逐字段解码或复制到已对齐对象。
static 局部变量具有静态存储期,所有调用共享同一对象。若函数被任务、中断或递归重入,共享读改写就会竞争;把状态放进调用者提供的上下文,或明确用同步保护,才能支持独立实例。
回调通常应与 void *context、调用上下文约定和所有权规则一起注册。注销要防止回调正在执行,可用引用计数、同步屏障或事件循环串行化;绝不能保存已经失效的栈地址。
可重入强调函数尚未返回时再次进入仍正确,通常不能依赖未保护的共享可变状态;线程安全可借助锁实现,但持锁函数未必可重入;中断安全还要求调用上下文、阻塞和时延都符合 ISR 约束。
协议必须明确每个多字节字段的线序和长度,编码、解码时逐字段转换并做边界检查,不能 memcpy 整个结构体。浮点和位域还要明确表示格式,测试应包含固定黄金字节序列。
小于 int 的整数类型参与大多数算术和位运算前会先做整数提升,因此 `~value` 通常得到 int 宽度的结果。应先在提升后的类型中计算,再用明确掩码或经过范围验证的转换取得目标位宽。