在 这个问题有人建议在 评论 我应该 不 投下结果 malloc
,即
int *sieve = malloc(sizeof(int) * length);
而不是:
int *sieve = (int *) malloc(sizeof(int) * length);
为什么会这样呢?
在 这个问题有人建议在 评论 我应该 不 投下结果 malloc
,即
int *sieve = malloc(sizeof(int) * length);
而不是:
int *sieve = (int *) malloc(sizeof(int) * length);
为什么会这样呢?
没有;您 别 投下结果,因为:
void *
在这种情况下,会自动安全地提升为任何其他指针类型。<stdlib.h>
。这可能会导致崩溃(或者更糟糕的是, 不 导致崩溃,直到稍后在代码的一些完全不同的部分)。考虑如果指针和整数的大小不同会发生什么;然后你通过强制转换隐藏了一个警告,可能会丢失你返回的地址。注意:从C11开始,隐式函数从C中消失,并且这一点不再相关,因为没有自动假设未声明的函数返回 int
。作为澄清,请注意我说“你不投”,而不是“你不投。” 需要 在我看来,即使你做对了也没有把演员包括在内。这样做没有任何好处,但是一堆潜在的风险,包括演员表明你不知道关于风险。
还要注意,正如评论员指出的那样,上面谈到的是直C,而不是C ++。我非常坚信C和C ++是不同的语言。
要进一步添加,您的代码会不必要地重复类型信息(int
)这可能会导致错误。最好取消引用用于存储返回值的指针,将两者“锁定”在一起:
int *sieve = malloc(length * sizeof *sieve);
这也移动了 length
在前面增加可见性,并删除多余的括号 sizeof
;他们 只需要 当参数是类型名称时。许多人似乎不知道(或忽略)这一点,这使得他们的代码更加冗长。记得: sizeof
不是功能! :)
在移动的同时 length
到前面 可能 在一些极少数情况下提高可见性,还应注意在一般情况下,将表达式编写为:
int *sieve = malloc(sizeof *sieve * length);
自从保持 sizeof
首先,在这种情况下,确保至少进行乘法运算 size_t
数学。
比较: malloc(sizeof *sieve * length * width)
与 malloc(length * width * sizeof *sieve)
第二个可能会溢出 length * width
什么时候 width
和 length
是比较小的类型 size_t
。
在C中,您不需要转换返回值 malloc
。返回void的指针 malloc
自动转换为正确的类型。但是,如果您希望使用C ++编译器编译代码,则需要进行强制转换。社区中的首选替代方案是使用以下内容:
int *sieve = malloc(sizeof *sieve * length);
如果您改变类型,还可以让您不必担心改变表达式的右侧 sieve
。
人们已经指出,演员阵容很糟糕。特别是指针转换。
您 做 演员,因为:
type *
与 type **
。#include
一个合适的头文件未命中 森林里的树木。这就像说“不要担心你没有要求编译器抱怨没有看到原型这一事实 - 那令人讨厌的stdlib.h是真正重要的事情要记住!”malloc()
当有一个演员时,错误被捕获得更快。与断言一样,显示意图的注释可以减少错误。 正如其他人所说,C不是必需的,而是C ++。如果您认为要使用C ++编译器编译C代码,出于某种原因,您可以使用宏,例如:
#ifdef __cplusplus
# define NEW(type, count) ((type *)calloc(count, sizeof(type)))
#else
# define NEW(type, count) (calloc(count, sizeof(type)))
#endif
这样你仍然可以以非常紧凑的方式编写它:
int *sieve = NEW(int, 1);
它将为C和C ++编译。
来自 维基百科
铸造的优点
包括强制转换可能允许C程序或函数编译为C ++。
演员版允许1989年之前版本的malloc最初返回char *。
如果目标指针类型发生变化,则转换可以帮助开发人员识别类型大小调整中的不一致性,特别是如果指针远离malloc()调用(尽管现代编译器和静态分析器可以在不需要强制转换的情况下警告此类行为)。
铸造的缺点
根据ANSI C标准,演员阵容是多余的。
添加强制转换可能会掩盖包含标题的失败 stdlib.h中,在 找到了malloc的原型。在没有 对于malloc的原型,标准要求C编译器 假设malloc返回一个int。如果没有演员表,则会发出警告 将此整数赋给指针时发出;然而,有 演员,这个警告没有产生,隐藏了一个bug。一定的 体系结构和数据模型(例如64位系统上的LP64,其中 long和指针是64位,int是32位),这个错误可以 实际上会导致未定义的行为,如隐式声明的那样 malloc返回32位值,而实际定义的函数 返回64位值。取决于调用约定和内存 布局,这可能会导致堆栈粉碎。这个问题不太可能发生 在现代编译器中被忽视,因为它们统一产生 警告已使用未声明的功能,因此会发出警告 仍然出现。例如,GCC的默认行为是显示a 警告,显示“内置的不兼容的隐式声明 功能“无论演员是否存在。
如果指针的类型在其声明处被更改,则可以 另外,需要更改调用malloc和cast的所有行。
虽然 没有铸造的malloc是首选方法,大多数有经验的程序员选择它,你应该使用你想知道的问题。
即:如果你需要将C程序编译为C ++(虽然这些是单独的语言),你应该使用 malloc
铸造。
在C中,您可以隐式地将void指针转换为任何其他类型的指针,因此不需要强制转换。使用一个可能会向不经意的观察者建议,有一些原因需要一个,这可能会产生误导。
你没有强制转换malloc的结果,因为这样做会给你的代码带来无意义的混乱。
人们投射malloc结果的最常见原因是因为他们不确定C语言的工作原理。这是一个警告信号:如果您不知道特定语言机制的工作原理,那么 别 猜一下。查找或询问Stack Overflow。
一些评论:
可以将void指针转换为任何其他指针类型,而不进行显式转换(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中,您将获得隐式转换 void*
到任何其他(数据)指针。
转换返回的值 malloc()
现在没有必要,但我想补充一点,似乎没有人指出:
在古代,也就是之前 ANSI C 提供 void *
作为通用类型的指针, char *
是这种用法的类型。在这种情况下,强制转换可以关闭编译器警告。
参考: C FAQ
投射结果不是强制性的 malloc
,因为它返回 void*
,和 void*
可以指向任何数据类型。
只是添加我的经验,学习计算机工程我看到我在C中写过的两三位教授总是施放malloc,但是我问的那个(有着巨大的简历和对C的理解)告诉我这绝对是不必要的但是以前只是绝对具体,并让学生进入绝对具体的心态。本质上,cast不会改变它的工作方式,它完全按照它所说的那样,分配内存,并且转换不会影响它,你获得相同的内存,即使你错误地将它转换为其他内容(并以某种方式避免编译器)错误)C将以相同的方式访问它。
编辑: 铸造有一定的意义。当您使用数组表示法时,生成的代码必须知道它有多少内存位置才能到达下一个元素的开头,这是通过强制转换实现的。通过这种方式,你知道对于一个双倍,你前进8个字节,而对于一个int,你去4,依此类推。因此,如果使用指针表示法则无效,在数组表示法中它变得必要。