当前位置:  开发笔记 > 前端 > 正文

在C中,为什么有些人在释放之前会抛出指针?

如何解决《在C中,为什么有些人在释放之前会抛出指针?》经验,为你挑选了6个好方法。

我正在研究一个旧的代码库,几乎每次调用free()都会在其参数上使用强制转换.例如,

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

其中每个指针都是相应的(和匹配的)类型.我完全没有理由这样做.这是非常古老的代码,所以我想知道它是否是K&R的东西.如果是这样,我实际上希望支持可能需要这个的旧编译器,所以我不想删除它们.

使用这些演员阵容有技术原因吗?我甚至没有看到使用它们的实用理由.在释放数据类型之前提醒自己有什么意义?

编辑:这个问题不是另一个问题的重复.另一个问题是这个问题的一个特例,如果亲密的选民能够阅读所有的答案,我认为这是显而易见的.

Colophon:我给出了"常量答案"的核对标记,因为这可能是为什么需要这样做的真正原因; 然而,关于它是一个ANSI C之前的习惯(至少在一些程序员中)的答案似乎是它在我的情况下使用的原因.很多人在这里有很多好处.感谢您的贡献.



1> Manos Nikola..:

如果指针是,则可能需要强制转换才能解析编译器警告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);编译器停止抱怨.


但为什么你需要动态分配常量内存?你永远不会用它!
@Nils_M这是一个简单的例子来说明问题.我在函数的实际代码中所做的是分配非常量内存,赋值,强制转换为const指针并返回它.现在,有一个指向预先指定的const内存的指针,有人必须释放.
错误的,如果一个函数将`const char*p`作为参数然后释放它,那么正确的做法是在调用free之前不要将`p`强制转换为`char*`.它不是首先声明它是'const char*p`,因为它*修改*`*p`并且应该相应地声明.(如果它需要一个const指针而不是指向const的指针,`int*const p`,你不需要*来执行,因为它实际上是合法的,因此在没有强制转换的情况下工作正常.)
@ m0skit0没有解释为什么有人会在释放之前强制转换为'float*'.我试过`free((void*)velocity);`用gcc 4.8.3.当然它不适用于古老的编译器
[示例](http://xmlrpc-c.sourceforge.net/doc/libxmlrpc.html):"这些子例程返回新的malloc内存中的字符串,由*stringValueP指向,您必须最终释放.有时,用于释放内存的OS函数被声明为指向非常量的指针作为其参数,因为*stringValueP是指向const的指针.

2> Lundin..:

预标准C void*只有char*,但只有你必须投射所有参数.如果你遇到古老的C代码,你可能会发现这样的演员阵容.

类似的问题与参考.

当第一个C标准被释放,malloc和free的原型不必改变char*void*,他们仍然有今天.

当然,在标准C中,这样的演员表是多余的,只是危害可读性.


但是为什么你要将"free"的参数转换为它已经存在的相同类型?
预标准C没有`空隙*`,但它没有函数原型任一,所以铸造free`的`参数仍然不必要即使在K&R(假设所有数据指针类型中使用的相同的表示).
由于评论中已经说明了多种原因,我认为这个答案没有意义.
@chux预标准的问题在于:没有任何义务.人们只是指着K&R的佳能书,因为这是他们唯一拥有的东西.正如我们从K&R第二版中的几个例子中可以看到的那样,K&R本身对于如何在标准C中使用参数"免费"工作(你不需要演员)感到困惑.我还没看过第一版,所以我不知道他们是否在80年代的标准时间之前感到困惑.
我不明白这个答案如何真正回答任何相关问题.最初的问题涉及到其他类型的强制转换,而不仅仅是`char*`.没有`void`的旧编译器会有什么意义?这样的演员会有什么成就?
@jwodder除非类型有一个限定符,如前面的答案所示,它可能没有理由,就这么简单.编写代码的人可能不明白为什么他们必须首先将参数强制转换为free().回到过去,人们做了很多愚蠢的事情,期间.例如,K&R书中有几个奇怪的参数示例,它们将`free`转换为`void*`,这既不是标准化也不是标准化后的任何意义.

3> egur..:

这是一个免费在没有强制转换的情况下会失败的示例:

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*代码.


`volatile`已经存在,因为C标准化了,如果不是更长的话.在C99中没有添加**.

4> chux - Reins..:

原因:1.通过使用free((sometype*) ptr),代码是明确的类型,指针应被视为free()调用的一部分.当free()用(自己动手)替换时,显式强制转换很有用DIY_free().

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

A DIY_free()是一种方法,特别是在调试模式下,对被释放的指针进行运行时分析.这通常与DIY_malloc()添加声望,全局内存使用计数等相关联.我的小组在出现更多现代工具之前使用了这种技术多年.它必须将被释放的项目转换为最初分配的类型.

    考虑到跟踪内存问题等花费了很多时间,像免费转换类型这样的小技巧将有助于搜索和缩小调试范围.


现代:Manos Nikolaidis @和@egur所述的避免constvolatile警告.我以为我会注意3场的效果预选赛:,,和.constvolatilerestrict

[编辑]增加char * restrict *rp2每@R ..评论

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;
}


`restrict`只是一个非问题,因为它放在哪里 - 它影响对象`rp`而不是指向类型.如果你改为`char*restrict*rp`,那就重要了.

5> zwol..:

这是另一种替代假设.

我们被告知该程序是在C89之前编写的,这意味着它无法解决与原型的某种不匹配问题free,因为不仅没有C89之前的事情,constvoid *没有这样的事情.C89之前的函数原型. stdlib.h本身就是委员会的一项发明.如果系统头文件free根本无法声明,他们就会这样做:

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

现在,关键点在于缺少函数原型意味着编译器没有进行参数类型检查.它应用了默认参数提升(仍然适用于可变参数函数调用的那些),就是这样.使每个呼叫站点的参数与被调用者的期望一致的责任完全在于程序员.

然而,这仍然并不意味着有必要free在大多数K&R编译器上提出论据.功能就像

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

应该已经正确编译.所以我认为我们在这里得到的是一个程序,用于处理异常环境中的错误编译器:例如,一个环境,sizeof(float *) > sizeof(int)编译器不会对指针使用适当的调用约定,除非你在这一点上强制转换它们电话.

我不知道有这样的环境,但这并不意味着没有这样的环境.想到的最可能的候选者是20世纪80年代早期用于8位和16位微处理器的简化"微型C"编译器.我也不会惊讶地发现早期的Crays有这样的问题.



6> 小智..:

free只接受非const指针作为参数.因此,在const指针的情况下,需要显式转换为非const指针.

无法在C中释放const指针

推荐阅读
手机用户2402852307
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有