有一个现有的C项目,有一些模块。每个模块都有一些全局变量和一些模块全局变量。我们有命名约定,例如MODULENAME_varname模块声明的全局变量和模块全局变量的Modulename_varname
如果我想为相应的全局和模块全局变量引入结构,我可以期待任何麻烦
吗?struct{
int moduleId;
type1 member1;
type2 member2;
...
} MODULE
和
struct{
int moduleId;
type1 member1;
type2 member2;
...
} Module
我更喜欢这样,而不是拥有一堆非结构化变量。这个想法是例如使用IDE列出所有成员变量以提高舒适度,或者只是使用某种意义上的函数
log(MODULE.moduleId,offset(MODULE,member1))
它可以增加RAM和程序代码的内存使用量。
结构填充
大多数体系结构要求变量以某种方式对齐。例如,32 位变量可能必须与可被 4 整除的地址对齐才能进行有效访问。
结构成员必须按声明顺序排列。这意味着编译器可能需要添加填充以保持数据访问速度。
struct { // Structure aligment is 4, to keep 'a' aligned
uint32_t a;
uint8_t b;
// Compiler inserts 3 byte padding here to keep 'c' aligned
uint32_t c;
//... other data here
} Module;
编译器可以以节省空间的方式在内存中排列"自由"变量。对于结构,您需要手动执行此操作。通常,这是通过从大到小或相反对成员进行排序来完成的。
请注意,许多编译器提供的结构打包不是解决方案。它通常会降低性能和/或增加程序大小。
可变放置
我正在简化这一点,但是:
通常,全局变量分为 2 组:零初始化和值初始化(零除外(。在启动 main 之前,必须初始化这两个。
对于零初始化变量,链接器通常只是将它们组合在一个位置,然后在调用 main 函数之前执行一个大memset
以将该区域中的所有字节设置为零。
值初始化的变量同样分组在其他位置,然后在程序启动时完成一个大memcpy
,从变量上的程序内存(按相同顺序排列(复制初始值。
如果将所有变量组合到结构中,则如果任何值不为零,则会强制从程序内存中复制所有初始值。
如果您在台式计算机上,这些可能不是问题。但是,在内存紧张的嵌入式系统上,必须考虑这些。
请注意,我并不是说这是一个坏主意。只要保持结构模块化,避免大型整体结构。