无法在函数外访问struct指针?GCC报“->操作数类型无效”错误
自定义malloc外部访问编译错误问题分析
问题描述
- 自定义malloc函数内部可正常访问buffer变量,读写数据无异常;但在函数外部尝试通过
*(buffer+索引)->data形式访问时,出现编译错误。
测试代码
mem* demo = malloc(2); if(*(demo+1)->data == 0x00) { // ... 执行相关操作 }
GCC交叉编译器报错信息
kernel.c:96:21: error: invalid type argument of '->' (have 'int')
96 | if(*(demo+1)->data == 0x00) {
代码实现(嵌入式环境,无标准库)
// 基于公共领域许可 // 注意:这是嵌入式系统环境,无标准库支持 typedef struct{ _Bool allocated; unsigned char data; } mem; mem memory[1000]; mem* malloc(size_t size){ mem* buffer[size]; unsigned int successfulCounts = 0; unsigned int bufferCounter = 0; for(unsigned int i = 0; i < sizeof(memory); i++){ // 找到可用内存块 if(memory[i].allocated == 0){ // 原注释:buffer是内存中的16个4字节项?表述存疑,保留原意 if(successfulCounts < sizeof(buffer)-sizeof(buffer-1)){ *(buffer+successfulCounts) = &memory[i]; successfulCounts++; memory[i].allocated = 1; }else{ break; } } } return buffer; } // ... 其他实现如free()、calloc()等代码
异常发现
- 将函数返回类型改为
unsigned char并返回*(buffer+1)时,可正常访问数据,无损坏。
问题根源与修复方案
1. 编译错误的直接原因:运算符优先级错误
->的优先级高于*和+,*(demo+1)->data实际会被解析为*( (demo+1)->data )。demo是mem*类型,demo+1指向第二个mem结构体,(demo+1)->data是unsigned char类型,对字符类型使用->完全非法,这就是编译报错的核心原因。
修正访问语法:
直接使用指针访问成员的正确写法,无需额外解引用:
if( (demo+1)->data == 0x00 ) { // ... 执行相关操作 }
或者等价的结构体解引用写法:
if( (*(demo+1)).data == 0x00 ) { // ... 执行相关操作 }
2. 隐藏的严重问题:返回栈局部变量指针
原malloc函数中,mem* buffer[size];是栈上的局部数组,函数执行完毕返回后,栈空间会被系统回收复用。返回这个局部数组的指针属于未定义行为,你测试时改返回类型能访问只是侥幸栈空间未被覆盖,实际运行中必然会出现内存访问异常、数据损坏等问题。
修复malloc函数:
嵌入式环境无标准库,我们直接从全局的memory数组中分配连续的内存块,无需栈上的buffer数组:
mem* malloc(size_t size){ // 确保size合法,避免越界 if(size == 0 || size > sizeof(memory)/sizeof(memory[0])){ return NULL; } // 寻找连续的size个未分配mem块 for(unsigned int i = 0; i <= sizeof(memory)/sizeof(memory[0]) - size; i++){ unsigned int j; // 检查当前起始位置开始的size个块是否都未分配 for(j = 0; j < size; j++){ if(memory[i+j].allocated != 0){ break; } } // 找到连续可用块 if(j == size){ // 标记为已分配 for(j = 0; j < size; j++){ memory[i+j].allocated = 1; } // 返回连续块的起始指针 return &memory[i]; } } // 没有足够内存返回NULL return NULL; }
修改后,demo指向的是全局memory数组中连续的size个mem结构体起始地址,demo+1可正确访问第二个结构体的成员,同时彻底避免了返回栈地址的未定义行为。
内容的提问来源于stack exchange,提问作者lplplplp
相关产品推荐
相关产品推荐

