在这个问题上,有人在评论中建议我不要使用malloc的结果。即,我应该这样做:
int *sieve = malloc(sizeof(*sieve) * length);
而不是:
int *sieve = (int *) malloc(sizeof(*sieve) * length);
为什么会这样?
在这个问题上,有人在评论中建议我不要使用malloc的结果。即,我应该这样做:
int *sieve = malloc(sizeof(*sieve) * length);
而不是:
int *sieve = (int *) malloc(sizeof(*sieve) * length);
为什么会这样?
当前回答
这就是GNU C库参考手册所说的:
您可以将malloc的结果存储到任何指针变量中强制转换,因为ISO C会自动将类型void*转换为另一个必要时的指针类型。但演员阵容在上下文中是必要的而不是赋值运算符,或者如果您可能希望代码运行在传统C。
事实上,ISO C11标准(第47页)是这么说的:
如果分配成功,则返回的指针将适当对齐它可以分配给指向任何类型对象的指针基本对齐要求,然后用于访问这样的对象或此类对象的数组(直到空间被显式释放)
其他回答
在C语言中,可以将空指针分配给任何指针,这就是为什么不应该使用类型转换的原因。如果您想要“类型安全”分配,我可以推荐以下宏函数,这些函数我总是在C项目中使用:
#include <stdlib.h>
#define NEW_ARRAY(ptr, n) (ptr) = malloc((n) * sizeof *(ptr))
#define NEW(ptr) NEW_ARRAY((ptr), 1)
有了这些,你可以简单地说
NEW_ARRAY(sieve, length);
对于非动态数组,第三个必须的函数宏是
#define LEN(arr) (sizeof (arr) / sizeof (arr)[0])
这使得阵列环路更加安全和方便:
int i, a[100];
for (i = 0; i < LEN(a); i++) {
...
}
这取决于编程语言和编译器。如果在C中使用malloc,则无需键入cast,因为它会自动键入cast。然而,如果您使用的是C++,那么应该键入cast,因为malloc将返回void*类型。
您不需要强制转换malloc的结果,因为这样做会给代码增加无意义的混乱。
人们之所以选择malloc的结果,最常见的原因是他们不确定C语言是如何工作的。这是一个警告信号:如果你不知道特定的语言机制是如何工作的,那么就不要猜测。查找或询问堆栈溢出。
一些意见:
空指针可以转换为任何其他指针类型,而无需显式转换(C11 6.3.2.3和6.5.16.1)。但是,C++不允许在void*和另一个指针类型之间进行隐式转换。因此,在C++中,演员阵容是正确的。但是如果你用C++编程,你应该使用new而不是malloc()。而且您永远不应该使用C++编译器编译C代码。如果需要使用相同的源代码同时支持C和C++,请使用编译器开关来标记差异。不要试图用相同的代码来满足两种语言标准,因为它们不兼容。如果C编译器因为忘记包含标头而找不到函数,则会出现编译器/链接器错误。因此,如果您忘记包含<stdlib.h>,这没什么大不了的,您将无法构建您的程序。在遵循超过25年的标准版本的古代编译器上,忘记包含<stdlib.h>将导致危险行为。因为在那个古老的标准中,没有可见原型的函数隐式地将返回类型转换为int。显式地从malloc转换结果将隐藏这个错误。但这真的不是问题。你不是在使用一台25年前的计算机,那么你为什么要使用一台有25年历史的编译器呢?
正如其他人所说的,它不是C所需要的,而是C++所需要的。包括强制转换可以允许C程序或函数编译为C++。在C中,这是不必要的,因为void*会自动安全地升级为任何其他指针类型。但如果你当时就投了,如果你忘了包括,它会隐藏一个错误stdlib.h。这可能会导致崩溃(更糟的是,不会导致崩溃直到稍后在代码的某个完全不同的部分)。因为stdlib.h包含找到malloc的原型。在由于没有malloc的原型,标准要求C编译器假设malloc返回int。如果没有强制转换当该整数被分配给指针时发出警告;然而,在演员阵容中,这个警告并没有产生,隐藏了一个bug。
加上我学习计算机工程的经验,我发现我见过的两三位教授总是用C语言写作,但我问的那位教授(有着丰富的简历和对C语言的理解)告诉我,这是绝对没有必要的,但只用于绝对具体,并让学生们养成绝对具体的心态。从本质上讲,强制转换不会改变它的工作方式,它完全按照它所说的做,分配内存,强制转换不影响它,你会得到相同的内存,即使你错误地将它强制转换为其他东西(并以某种方式规避编译器错误),C也会以同样的方式访问它。
编辑:铸造有一定的意义。当您使用数组表示法时,生成的代码必须知道要到达下一个元素的开头,需要前进多少个内存位置,这是通过强制转换实现的。通过这种方式,您可以知道,对于double,您可以提前8个字节,而对于int,则可以提前4个字节,依此类推。因此,如果您使用指针表示法,则不会产生任何影响,在数组表示法中,这是必要的。