在 C 语言中,为什么有些人在释放指针之前先抛出指针呢?

我正在使用一个旧的代码库,几乎每次调用 free ()都会对其参数进行强制转换。比如说,

free((float *)velocity);
free((float *)acceleration);
free((char *)label);

其中每个指针都是对应(和匹配)类型。我觉得这样做毫无意义。这是很古老的代码,所以我想知道这是不是绑架勒索。如果是这样,我实际上希望支持可能需要这样做的旧编译器,所以我不想删除它们。

使用这些石膏是否有技术上的原因?我甚至看不出有什么实际的理由使用它们。在释放数据类型之前提醒自己数据类型的意义何在?

编辑: 这个问题是 没有另一个问题的重复。另一个问题是这个问题的一个特例,我认为如果关系密切的选民已经阅读了所有的答案,这个问题是显而易见的。

Colophon: 我给出了一个为什么仍然需要这样做的原因的答案,然而,它是一个前 ANSI C 定制(至少在一些程序员中)的答案似乎是它在我的案例中使用的原因。如果有两个对勾,他们都会得到一个。这里的很多人都有很多优点。谢谢你的贡献。

14985 次浏览

这里有一个例子,如果没有演员阵容,自由将会失败:

volatile int* p = (volatile int*)malloc(5 * sizeof(int));
free(p);        // fail: warning C4090: 'function' : different 'volatile' qualifiers
free((int*)p);  // success :)
free((void*)p); // success :)

在 C 语言中你可以得到一个警告(在 VS2012中得到一个) ,在 C + + 中你会得到一个错误。

除了少数情况,铸造只是膨胀的代码..。

编辑: 我铸造到 void*而不是 int*演示失败。它的工作原理与将 int*隐式转换为 void*相同。增加了 int*代码。

如果指针为 const,则可能需要进行强制转换来解析编译器警告。下面是一个代码示例,它在不强制执行 free 参数的情况下导致警告:

const float* velocity = malloc(2*sizeof(float));
free(velocity);

编译器(gcc 4.8.3)会说:

main.c: In function ‘main’:
main.c:9:5: warning: passing argument 1 of ‘free’ discards ‘const’ qualifier from pointer target type [enabled by default]
free(velocity);
^
In file included from main.c:2:0:
/usr/include/stdlib.h:482:13: note: expected ‘void *’ but argument is of type ‘const float *’
extern void free (void *__ptr) __THROW;

如果使用 free((float*) velocity);,编译器将停止抱怨。

Free 只接受非常量指针作为参数。因此,对于常量指针,需要显式强制转换为非常量指针。

无法释放 C 中的常量指针

标准 C 之前没有 void*,只有 char*,因此必须强制转换所有传递的参数。如果遇到古代 C 代码,可能会发现这样的强制转换。

类似的问题与参考文献

当第一个 C 标准发布时,malloc 和 free 的原型从使用 char*改为使用至今的 void*

当然,在标准 C 中,这样的强制转换是多余的,只会损害可读性。

旧理由: 1。通过使用 free((sometype*) ptr),代码明确指出了指针应该被视为 free()调用的一部分的类型。当用(自己动手) DIY_free()替换 free()时,显式强制转换非常有用。

#define free(ptr) DIY_free(ptr, sizeof (*ptr))

DIY_free()是一种对释放的指针进行运行时分析的方法,特别是在调试模式下。这通常与 DIY_malloc()配对,以添加句子、全局记忆使用计数等。在更多现代工具出现之前,我的团队已经使用这种技术很多年了。它要求被释放的项被强制转换为最初分配的类型。

  1. 考虑到花费大量的时间来跟踪内存问题等,释放类型等小技巧将有助于搜索和缩小调试范围。

现代的: 避免 constvolatile警告所处理的 Manos Nikolaidis@@ egur。我想我会注意到的效果3 资格赛: constvolatile,和 restrict

[编辑]每个 @ R. . 評論增加 char * restrict *rp2

void free_test(const char *cp, volatile char *vp, char * restrict rp,
char * restrict *rp2) {
free(cp);  // warning
free(vp);  // warning
free(rp);  // OK
free(rp2);  // warning
}


int main(void) {
free_test(0,0,0,0);
return 0;
}

这里有另一个假设。

我们被告知这个程序是在 C89之前编写的,这意味着它不可能与 free的原型不匹配,因为不仅在 C89之前没有 constvoid *这样的东西,在 C89之前也没有 功能原型这样的东西。stdlib.h本身就是委员会的发明。如果系统头部费心声明 free,他们会这样做:

extern free();  /* no `void` return type either! */

现在,这里的关键点是没有函数原型意味着编译器执行了 无参数类型检查。它应用了默认参数提升(仍然适用于可变参数函数调用) ,就是这样。程序员负责使每个调用站点的参数符合被调用方的期望值。

但是,这仍然不意味着需要在大多数 K & R 编译器上将参数强制转换为 free。类似于

free_stuff(a, b, c)
float *a;
char *b;
int *c;
{
free(a);
free(b);
free(c);
}

应该是正确编译的。所以我认为我们在这里得到的是一个程序编写来应对一个不寻常的环境中的错误编译器: 例如,在这个环境中,sizeof(float *) > sizeof(int)和编译器 不会对指针使用适当的调用约定,除非你在调用的时候对它们进行强制转换。

我不知道有这样的环境,但这并不意味着没有这样的环境。最有可能出现在我们脑海中的是上世纪80年代初用于8位和16位微处理器的缩减版“微型 C”编译器。我也不会对早期的克雷斯有这样的问题感到惊讶。