现在在人们开始将它标记为dup之前,我已经阅读了以下所有内容,其中没有一个提供我正在寻找的答案:
C FAQ和上述问题的许多答案都引用了一个神秘的错误,即铸造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;
}
Run Code Online (Sandbox Code Playgroud)
用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
Run Code Online (Sandbox Code Playgroud)
那么,任何人都可以提供一个特定的代码示例,说明由于转换malloc返回值而可能发生的编译或运行时错误,或者这仅仅是一个城市传奇?
编辑我在这个问题上遇到了两个写得很好的论点:
Fer*_*yer 66
您不会收到编译器错误,但会收到编译器警告.作为您引用的来源(特别是第一个),在使用强制转换而不包括时,您可能会遇到不可预测的运行时错误.stdlib.h
所以你身边的错误不是演员,而是忘记包括stdlib.h.编译器可以假设malloc是一个函数返回int,因此转换void*通过实际返回的指针malloc来int,然后由于显式转换指针类型.在某些平台上,int指针可能占用不同的字节数,因此类型转换可能会导致数据损坏.
幸运的是,现代编译器会发出警告,指出您的实际错误.查看gcc您提供的输出:它警告您隐式声明(int malloc(int))与内置不兼容malloc.所以gcc似乎malloc甚至没有知道stdlib.h.
抛出演员以防止这种错误与写作大致相同
if (0 == my_var)
Run Code Online (Sandbox Code Playgroud)
代替
if (my_var == 0)
Run Code Online (Sandbox Code Playgroud)
因为后者可能会导致一个严重的错误,如果一个会混淆=和==,而第一个将导致编译错误.我个人更喜欢后者的风格,因为它更好地反映了我的意图,我不倾向于犯这个错误.
转换返回的值也是如此malloc:我更喜欢在编程中明确,我通常会仔细检查以包含我使用的所有函数的头文件.
AnT*_*AnT 45
malloc虽然在我看来,它比知名的低级问题(比如在缺少声明时截断指针)更重要,但是反对强制转换结果的一个好的高级别论据往往没有被提及.
一个好的编程习惯是编写代码,尽可能与类型无关.这尤其意味着,应尽可能少地在代码中提及类型名称,或者最好不要提及.这适用于强制转换(避免不必要的强制转换),类型作为参数sizeof(避免使用类型名称sizeof),通常还有所有其他对类型名称的引用.
类型名称属于声明.类型名称应尽可能限于声明,仅限于声明.
从这个角度来看,这段代码很糟糕
int *p;
...
p = (int*) malloc(n * sizeof(int));
Run Code Online (Sandbox Code Playgroud)
这要好得多
int *p;
...
p = malloc(n * sizeof *p);
Run Code Online (Sandbox Code Playgroud)
不仅仅是因为它"不会导致结果malloc",而是因为它是独立于类型的(或者类型无关,如果你愿意的话),因为它会自动调整自身适用于p声明的任何类型,而不需要任何干预用户.
unw*_*ind 18
假设非原型函数返回int.
所以你要投射int指针.如果指针比int平台上的指针宽,那么这是一种高风险的行为.
当然,有些人认为警告是错误的,即代码应该在没有它们的情况下进行编译.
就个人而言,我认为你不需要转换void *为另一种指针类型的事实是C中的一个特性,并考虑要破坏的代码.
Pee*_*oot 11
如果在64位模式下编译时执行此操作,则返回的指针将被截断为32位.
编辑:抱歉太简短了.这是用于讨论目的的示例代码片段.
main()
{
char * c = (char *)malloc(2) ;
printf("%p", c) ;
}
假设返回的堆指针大于int中可表示的值,比如说0xAB00000000.
如果malloc没有原型返回指针,则返回的int值最初将位于某个寄存器中,并设置了所有有效位.现在编译器说,"好吧,我如何将int和int转换为指针".这将是一个符号扩展或低阶32位的零扩展,它已被告知malloc通过省略原型"返回".由于int已签名,我认为转换将是符号扩展,在这种情况下将转换为零.如果返回值为0xABF0000000,您将获得一个非零指针,当您尝试取消引用它时,这也会带来一些乐趣.
可重用软件规则:
在编写使用 malloc() 的内联函数时,为了使其也可重用于 C++ 代码,请进行显式类型转换(例如 (char*));否则编译器会抱怨。
| 归档时间: |
|
| 查看次数: |
16420 次 |
| 最近记录: |