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

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

  • C FAQ:铸造malloc的返回值有什么问题?
  • SO:我应该明确地施放malloc()的返回值吗?
  • SO:C中不需要的指针
  • SO:我投了malloc的结果吗?
  • 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("%sn", 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的返回值而可能发生的编译或运行时错误,还是仅仅是城市传说?

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

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

  • 你不会得到一个编译器错误 ,而是一个编译器警告 。 作为您引用的来源(特别是第一个),您可以在不使用stdlib.h情况下使用转换时发生不可预知的运行时错误

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

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

    抛出演员以防止这种错误与写作大体上是相同的推理

    if (0 == my_var)
    

    代替

    if (my_var == 0)
    

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

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


    对于malloc的结果,其中一个较好的更高级别的观点经常被忽略,尽管在我看来,它比知名的底层问题更重要(比如声明丢失时截断指针) 。

    一个好的编程习惯是编写代码,它尽可能的与类型无关。 这意味着,尤其应该在代码中尽可能少地提及类型名称,或者最好不要提及类型名称。 这适用于强制类型转换(避免不必要的强制类型转换),作为sizeof参数的sizeof (避免在sizeof使用类型名称)以及通常所有其他对类型名称的引用。

    类型名称属于声明。 尽可能多的,类型名称应该限制在声明中,并且仅限于声明。

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

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

    这样好多了

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

    不只是因为它“不投结果malloc ”,而是因为它的类型是独立的(或类型agnositic,如果你喜欢),因为它会自动调整自己到任何类型的p声明了,而不需要任何来自用户的干预。


    假定非原型函数返回int

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

    此外,当然,有些人认为警告是错误的,即代码应该在没有它们的情况下编译。

    就我个人而言,我认为你不需要将void *为另一种指针类型是C中的一个特性,并且考虑那些被破坏的代码。

    链接地址: http://www.djcxy.com/p/4857.html

    上一篇: Specifically, what's dangerous about casting the result of malloc?

    下一篇: Getting a stack overflow exception when declaring a large array