在这个问题上,有人在评论中建议我不要使用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);
为什么会这样?
当前回答
在C语言中,您得到了从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年历史的编译器呢?
不,您不强制转换malloc()的结果。
一般来说,你不会向虚空施法或从虚空施法。
不这样做的一个典型原因是#include<stdlib.h>失败可能会被忽略。这在很长一段时间内不再是问题,因为C99使隐式函数声明非法,所以如果您的编译器至少符合C99,您将得到一条诊断消息。
但有一个更强烈的理由不引入不必要的指针强制转换:
在C语言中,指针转换几乎总是一个错误。这是因为以下规则(N1570中的§6.5 p7,C11的最新草案):
对象的存储值只能由左值表达式访问,左值表达式具有以下类型:-与对象的有效类型兼容的类型,-与对象的有效类型兼容的类型的限定版本,-一种类型,它是与对象-类型,该类型是与对象的有效类型,-一种聚合或联合类型,在其成员(递归地包括子集合或包含联合的成员),或-字符类型。
这也称为严格别名规则。因此,以下代码是未定义的行为:
long x = 5;
double *p = (double *)&x;
double y = *p;
有时令人惊讶的是,以下内容也是:
struct foo { int x; };
struct bar { int x; int y; };
struct bar b = { 1, 2};
struct foo *p = (struct foo *)&b;
int z = p->x;
有时,您确实需要强制转换指针,但考虑到严格的别名规则,您必须非常小心。因此,代码中出现的任何指针强制转换都需要重新检查其有效性。因此,您永远不会编写不必要的指针强制转换。
tl;博士
简而言之:因为在C语言中,指针强制转换的任何出现都会给需要特别注意的代码带来危险,所以您不应该编写不必要的指针强制转换。
附带说明:
在某些情况下,您实际上需要转换为void*,例如,如果您想要打印指针:int x=5;printf(“%p\n”,(void*)&x);这里强制转换是必要的,因为printf()是一个可变函数,所以隐式转换不起作用。在C++中,情况不同。在处理派生类的对象时,强制转换指针类型有些常见(也是正确的)。因此,在C++中,与void*的转换不是隐式的,这是有意义的。C++有一整套不同风格的铸造。
你会选演员,因为:
它使您的代码在C和C++之间更具可移植性,正如SO的经验所示,许多程序员声称,当他们真正用C++(或C加本地编译器扩展)编写时,他们是在用C编写。如果不这样做,可能会隐藏一个错误:请注意所有的so示例,它们混淆了何时写入类型*和类型**。它会让你注意不到你没有#包含一个合适的头文件,这一想法让你错过了树的森林。这与说“不要担心你没能让编译器抱怨没有看到原型的事实——讨厌的stdlib.h才是真正需要记住的重要东西!”它强制进行额外的认知交叉检查。它将(所谓的)所需类型放在您对该变量的原始大小所做的算术旁边。我敢打赌,你可以做一个SO研究,表明malloc()错误在有演员时被捕获的速度要快得多。与断言一样,揭示意图的注释可以减少错误。以机器可以检查的方式重复自己的行为通常是一个好主意。事实上,这就是断言,使用强制转换就是断言。断言仍然是我们获得正确代码的最通用技术,因为图灵多年前就提出了这个想法。
尽可能在C语言中编程时最好做的事情是:
通过C编译器编译程序,并打开所有警告-Wall并修复所有错误和警告确保没有声明为auto的变量然后使用带有-Wall和-std=C++11的C++编译器对其进行编译。修复所有错误和警告。现在再次使用C编译器进行编译。您的程序现在应该在没有任何警告的情况下编译,并且包含更少的错误。
这个过程使您可以利用C++严格的类型检查,从而减少错误的数量。特别是,此过程强制您包含stdlib.否则您将得到
malloc未在此范围内声明
并且还强制你使用malloc的结果,否则你会得到
从void*到T的转换无效*
或者你的目标类型是什么。
用C而不是C++编写的唯一好处是
C具有明确规定的ABIC++可能会生成更多代码[异常、RTTI、模板、运行时多态性]
请注意,在理想情况下,当使用C所共有的子集和静态多态特性时,第二个缺点应该消失。
对于那些觉得C++严格规则不方便的人,我们可以使用带有推断类型的C++11特性
auto memblock=static_cast<T*>(malloc(n*sizeof(T))); //Mult may overflow...
不强制强制强制强制转换malloc的结果,因为它返回void*,并且void*可以指向任何数据类型。