【问题标题】:Avoiding freeing a string literal避免释放字符串文字
【发布时间】:2015-12-16 07:17:42
【问题描述】:

如果您有一个 C 中的函数,该函数对传递给它的任何内容都拥有所有权,例如将struct 按值添加到向量缓冲区的函数,并且此结构值包含指向字符数组的成员指针(一个字符串)。

在缓冲区的清理例程期间,它应该释放它拥有的字符串,但是如果一些字符串是在运行时分配的,而另一些是在编译时使用字符串字面量分配的。

没有安全且标准(非专有)的方法来检测 char* 是否指向只读内存,那么这个假设的 freeVector 函数与指向 char 缓冲区的指针有什么关系?

struct Element {
    int   id;
    char* name;
}

struct Vector {
    size_t maxIndex;
    size_t length;
    struct Element buffer[];
}

void addToVector(struct Vector* vector, struct Element element) {
    // lazy-reallocation logic here if maxIndex => length
    vector->buffer[ vector->maxIndex++ ] = element; // by-value copy
}

void freeVector(struct Vector* vector) {
    for(size_t i = 0; i < vector->maxIndex; i++ ) {
        free( vector->buffer[ i ].name ); // segfault/AV if name is a literal
    }
}

【问题讨论】:

  • 您的元素结构需要一个标志,让您知道是否可以释放该名称。
  • @AlexisWilke 很好,是的,但我想知道是否有更好的方法。
  • 有一些专有的方法可以知道指针是在堆中还是在启动数据中,但它可能会更慢(在 Unix 下,它只是一个指针比较,但 Windows 需要 API 调用...... )既然你说“非专有”......
  • 您的其他选项是 (1) 在将它们传递给您的数据结构之前始终使用 strdup 字符串文字(如果字符串文字很少见,可能会更便宜)或 (2) 在运行时添加垃圾收集器(允许 const 字符串的零拷贝共享)。
  • 请注意,字符串文字并不是问题的唯一来源:如果您传递本地字符数组、文件范围 (static) 或全局字符,则会遇到不同的问题数组到代码。所有这些都不是malloc()和亲戚分配的,因此不能用free()释放。此外,局部变量容易超出范围,并且它们的空间将被重用,从而导致各种问题。到目前为止,最简单的方法是让你的代码始终复制它传递的字符串——决定谁将分配的字符串释放给调用代码。

标签: c malloc free


【解决方案1】:

C 的好处和坏处在于它完全由你决定。两种选择是在堆上分配所有内容,并定义一个胖指针类型,其中包含一些说明每个实例是否需要释放的信息。一个聪明但不可移植的实现可能会使用指针本身的低位,因为对于许多体系结构,所有指针的底部 2 位或更多位始终为零。垃圾收集器几乎永远使用这个技巧来区分指针和未装箱的离散类型(商业中的fixnums)。

如果您允许多个指针指向同一个对象(想想图形数据结构),那么根据您的观点,事情会变得更加复杂或有趣。为此,您可能需要一个垃圾收集方案:obstacks、引用计数、标记和清除、arena 复制等。其他语言倾向于将其中之一作为内置或(如在 C++ 中)语言特性故意提供旨在支持自己实施一个或多个。用 C,没那么多...

【讨论】:

    猜你喜欢
    • 2021-03-09
    • 1970-01-01
    • 2019-06-08
    • 2016-03-27
    • 2012-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多