具体来说,铸造malloc的结果有什么危险?

现在,在人们开始标记这个dup之前,我已经阅读了以下所有内容,但是没有一个提供我正在寻找的答案:

  1. C FAQ:铸造malloc的返回值有什么问题?
  2. SO:我应该明确地施放malloc()的返回值吗?
  3. SO:C中不需要的指针
  4. SO:我inputmalloc的结果吗?

C常见问题和上述问题的很多答案都引用了malloc的返回值可以隐藏的神秘错误; 然而,他们没有一个在实践中给出这样一个错误的具体例子。 现在请注意,我说错误 ,而不是警告

现在给出以下代码:

 #include <string.h> #include <stdio.h> // #include <stdlib.h> int main(int argc, char** argv) { char * p = /*(char*)*/malloc(10); strcpy(p, "hello"); printf("%s\n", p); return 0; } 

使用gcc 4.2编译上面的代码,使用和不使用强制转换都会给出相同的警告,并且程序正确执行并在两种情况下都提供相同的结果。

 anon@anon:~/$ gcc -Wextra nostdlib_malloc.c -o nostdlib_malloc nostdlib_malloc.c: In function 'main': nostdlib_malloc.c:7: warning: incompatible implicit declaration of built-in function 'malloc' anon@anon:~/$ ./nostdlib_malloc hello 

那么,任何人都可以给出一个特定的编译或者运行时错误代码的例子,这个错误可能是因为malloc的返回值而产生的,或者这只是一个城市传说?

编辑我已经遇到了两个关于这个问题写得很好的论据:

  1. 有利于 Casting:CERT咨询: 立即将内存分配函数调用的结果转换为指向分配types的指针
  2. 针对Casting (2012年2月14日发生404错误:使用Internet Archive Wayback Machine复制自2010-01-27。{2016-03-18:“由于robots.txt导致页面无法被抓取或显示”)}

你不会得到一个编译器错误 ,而是一个编译器警告 。 作为引用的来源(特别是第一个 ),当使用转换时, 如果不包含stdlib.h可能会导致无法预料的运行时错误

所以错误在你身边不是演员,但忘记包含stdlib.h 。 编译器可能会认为malloc是一个返回int的函数,因此由malloc实际返回的void*指针转换为int ,然后转换为指针types。 在某些平台上, int和指针可能会占用不同数量的字节,因此types转换可能会导致数据损坏。

幸运的是,现代编译器给出了指向你的实际错误的警告。 请参阅您提供的gcc输出:它会警告您隐式声明( int malloc(int) )与内置malloc不兼容。 所以即使没有stdlib.h gcc似乎也知道malloc

抛出演员,以防止这个错误大多是写作相同的原因

 if (0 == my_var) 

代替

 if (my_var == 0) 

因为后者可能会导致严重的错误,如果有人会混淆=== ,而第一个会导致编译错误。 我个人比较喜欢后者,因为它更好地反映了我的意图,我不倾向于犯这个错误。

对于转换由malloc返回的值也是如此:我更喜欢在编程中明确表示,我通常仔细检查包含所有我使用的函数的头文件。

其中一个反对malloc结果的较高层次的争论经常被忽略,尽pipe在我看来,它比着名的底层问题更重要(比如声明丢失时截断指针) 。

一个好的编程习惯是编写代码,尽可能的不依赖于types。 这意味着,特别是在代码中应尽可能less地提及types名称,或者最好不要提及types名称。 这适用于强制types转换(避免不必要的强制types转换),作为sizeof参数的sizeof (避免使用sizeoftypes名称),通常还包括对types名称的所有其他引用。

types名称属于声明。 尽可能地,types名称应该只限于声明,并且只限于声明。

从这个angular度来看,这一点代码是不好的

 int *p; ... p = (int*) malloc(n * sizeof(int)); 

这样好多了

 int *p; ... p = malloc(n * sizeof *p); 

不是简单的因为它“不会传递malloc的结果”,而是因为它是types无关的(或者types无关的,如果你喜欢的话),因为它自动调整自己到任何types的p声明,而不需要任何来自用户的干预。

假定非原型函数返回int

所以你正在投射一个int指针。 如果指针比你的平台上的int更宽,这是非常危险的行为。

此外,当然,有些人认为警告错误的,即代码应该编译没有他们。

就个人而言,我认为你不需要将void *为另一个指针types是C中的一个特性,并且考虑到了可以被破坏的代码。

如果以64位模式编译时执行此操作,则返回的指针将被截断为32位。

编辑:抱歉太短暂。 这里是一个用于讨论目的的示例代码片段。

主要()
 {
    char * c =(char *)malloc(2);
    printf(“%p”,c);
 }

假设返回的堆指针比int中可表示的东西大,比如0xAB00000000。

如果malloc没有原型返回一个指针,那么返回的int值最初将会被寄存器中的所有有效位设置。 现在编译器说,“好吧,我该如何转换和int指针”。 这将是低位32位的符号扩展或零扩展,它通过省略原型而被告知malloc“返回”。 由于int是有符号的,我认为转换将是符号扩展,在这种情况下,将值转换为零。 返回值为0xABF0000000时,您将得到一个非零指针,当您尝试对其进行解引用时,也会带来一些乐趣。

可重复使用的软件规则:

在编写使用malloc()的内联函数的情况下,为了使C ++代码也可以重用,请做一个明确的types转换(例如(char *)); 否则编译器会报错。

C中的void指针可以分配给任何指针而不需要显式的强制转换。 编译器会给出警告,但是可以通过将malloc()强制转换为相应的types来在C ++中重用 。 用outtypes转换也可以在C中使用,因为C没有严格的types检查 。 但是C ++是严格types检查的,因此需要在C ++中inputcast malloc()