C+YACC中变量被覆盖的原因是什么?
嘿,我来帮你排查下这个变量覆盖的问题,结合你贴的代码片段,大概率是这几个常见的坑导致的:
1. 字符串缓冲区复用搞的鬼
如果你的词法分析器(Flex/LEX)里用了静态字符数组来存标识符或者数值字符串,比如像下面这样:
// 假设LEX里的代码 static char buf[256]; // 匹配到数值或字符串时 strcpy(buf, yytext); yylval.e.value = buf;
那麻烦就来了——所有赋值操作里的value都会指向同一个buf缓冲区。每次新的赋值都会把buf里的内容覆盖掉,结果就是你存在variables数组里的所有指针,全指向这块不断被改写的内存,看起来就像旧变量的值被新变量覆盖了。
解决办法很简单:给每个变量的字符串值单独分配内存,用strdup最省事(它会自动malloc内存并复制字符串),或者手动malloc+strcpy也行:
// 在action函数处理ASSIGN动作时 int idx = tolower(id) - 'a'; // 先转成小写确保索引正确 variables[idx] = strdup(value); // 或者手动来 size_t val_len = strlen(value); variables[idx] = malloc(val_len + 1); if (variables[idx] != NULL) { strcpy(variables[idx], value); }
别忘了程序结束时遍历variables数组,用free把内存释放掉,不然会漏内存。
2. 临时栈变量的坑
如果在语义动作里,你把栈上的临时变量地址直接传给了action函数,比如:
// 某个YACC语义动作里 char temp_buf[256]; sprintf(temp_buf, "%d", some_int_value); action(ASSIGN, 'x', temp_buf);
等这个语义动作执行完,栈上的temp_buf就被销毁了,variables['x'-'a']就变成了悬空指针。后面其他函数调用的栈操作很可能会覆盖这块内存,结果就是变量值莫名其妙被篡改。
同样,解决思路还是给值分配独立的堆内存,别用栈上的临时变量当持久化的指针。
3. 标识符索引算错了
你的variables是大小26的数组,对应26个字母,但如果处理标识符时没统一大小写,或者索引计算错了,比如:
// 错误示例:直接用字符ASCII码当索引 variables[id] = value; // 比如id是'x',ASCII是120,直接越界访问数组
这种越界操作会乱改数组外面的内存,可能无意中覆盖其他变量的指针,或者used_ids数组的内容,表现出来就是变量值被覆盖。
一定要把标识符转成正确的0-25索引,比如统一转小写后减'a':
int idx = tolower(id) - 'a'; if (idx < 0 || idx >= 26) { yyerror("Invalid variable name - only a-z allowed"); return 1; } // 再操作variables[idx]
4. 表达式结构体的内存复用问题
你的%union里定义了struct expression,如果这个结构体里的value指针被多个表达式节点复用,或者没给每个表达式的value分配独立内存,也会导致后续操作覆盖之前的变量值。比如多个表达式共享同一个value指针,改一个就全变了。
建议在生成表达式节点的时候,确保每个value都是单独分配的内存,别指向同一个临时缓冲区。
你可以先检查LEX里的缓冲区使用方式,还有action函数里赋值时的内存处理,这俩地方是变量覆盖问题的重灾区。
内容的提问来源于stack exchange,提问作者Doasy

