我正在浏览野牛手册中的mfcalc示例,我有一个关于符号表的问题。
特别是在例程中,我们有对putsym()的调用,但我没有看到对malloc的相应调用。我们需要手动释放符号表(free在下面的代码中)还是工具自动处理?

symrec *
putsym (char const *sym_name, int sym_type)
{
  symrec *ptr = (symrec *) malloc (sizeof (symrec));
  ptr->name = (char *) malloc (strlen (sym_name) + 1);
  strcpy (ptr->name,sym_name);
  ptr->type = sym_type;
  ptr->value.var = 0; /* Set value to 0 even if fctn.  */
  ptr->next = (struct symrec *)sym_table;
  sym_table = ptr;
  return ptr;
}

最佳答案

“工具”对你的行为一无所知。
我引用“这个工具”是因为实际上,在大多数解析项目中至少有两个代码生成工具:一个解析器生成器(本例中是bison)和一个scanner生成器((f)lex)。mfcalc示例使用手工构建的lexer来避免依赖于lex,尽管使用(f)lex可能更简单。在任何情况下,对符号表库的调用都在scanner中,与bison生成的代码完全无关。
当然,还有其他工具在发挥作用。例如,整个项目使用C编译器构建,并在某种托管环境中运行(使用C标准的词语);换句话说,操作系统和运行时支持库包含mallocfree的实现(尽管正如您所指出的,示例代码并不调用free)。
我最后提到这些是因为它们与你的问题有关。当进程终止时,将释放所有进程资源,包括其内存映像。(这不是C标准所要求的,但几乎所有托管环境都是这样工作的。)因此,如果要在程序终止之前使用内存,实际上不需要分配内存。
与全局变量一样,未释放的内存分配在同一时间非常常见。现在,这样的事情被认为是不好的实践(充其量),大多数程序员都会避免,但事实并非总是如此。曾经有一段时间,许多程序员认为,跟踪资源只是为了在程序终止前释放它们,或是跳过确保执行终止前清理所必需的步骤是浪费资源的。(即使在今天,许多程序员在发生不可恢复的错误时也只会插入对free()的调用,而不会费心跟踪和手动释放每个分配的内存块。尤其是在非生产代码中。)
不管您是否赞成这种编码风格,bison手册中的示例(以及许多其他类型的代码示例)都可以追溯到那个无辜的时代。
因此,本例中的符号表条目从未被释放。您的生产代码可能会做得更好,但它也应该使用更有效的数据结构,并避免依赖于(单个)全局上下文。但这些都与exit(1)试图说明的bison特性无关。

10-06 10:18