能否采用该种语法初始化全局结构体指针?
关于ESP8266/ESP32全局结构体指针初始化的疑问与解答
问题描述
我正在开发一款面向ESP8266/ESP32 SOC设备、对接Spotify API的程序。当前我通过以下函数使用calloc分配内存并初始化全局结构体指针:
void init_fun() { ... PLAYLISTS = calloc(1, sizeof(*PLAYLISTS)); assert(PLAYLISTS && "Error allocating memory"); DEVICES = calloc(1, sizeof(*DEVICES)); assert(DEVICES && "Error allocating memory"); ... }
想咨询是否可以采用以下语法直接初始化全局结构体指针:
/* Globally scoped variables definitions -------------------------------------*/ some_struct_t* PLAYLISTS = &(some_struct_t){0}; some_struct_t* DEVICES = &(some_struct_t){0};
解答
语法是合法的
你用的&(some_struct_t){0}是C99标准里的复合字面量写法,语法上完全没问题。它会生成一个匿名的some_struct_t实例,自动把所有成员置零,然后把这个实例的地址赋给全局指针。
两种写法的关键区别
- 内存位置不一样
calloc是从堆里分配内存:程序运行时才申请,之后可以用free释放,适合需要动态调整大小、或者运行中可能要销毁重建的结构体。- 全局复合字面量的结构体实例存在静态内存区(要么是只读段
.rodata,要么是全局数据段.data):这部分内存是程序一启动就占了的,没法手动释放,属于固定占用。
- 初始化时间不同
calloc的初始化是在你调用init_fun的时候才执行,属于运行时动态初始化。- 复合字面量的全局初始化是在程序启动阶段(早于
main函数)就完成了,属于静态初始化。
- 针对ESP平台的注意点
- ESP8266/ESP32的RAM本来就不多,静态内存区的东西会直接占用宝贵的RAM(如果是
.data段的话),堆内存反而能更灵活地调度。要是你的结构体比较大,用静态初始化可能会导致RAM不够用。 - 另外,ESP的RTOS环境里,多个任务访问这些全局结构体时,两种写法都要注意线程安全,但静态初始化的结构体不会有分配失败的问题(不用写
assert检查),而calloc可能因为堆内存不够分配失败。
- ESP8266/ESP32的RAM本来就不多,静态内存区的东西会直接占用宝贵的RAM(如果是
选型建议
- 如果你的结构体大小固定,运行期间不需要释放或者重建,用复合字面量的写法更简洁,完全可行。
- 如果结构体需要动态调整大小、后续要释放,或者担心静态内存占太多RAM,那还是保留原来的
calloc动态分配方式更稳妥。
内容的提问来源于stack exchange,提问作者Francisco Herrera
相关产品推荐
相关产品推荐

