为什么C++中的malloc()需要强制类型转换而C语言不需要?

50

我一直对这个问题很好奇 - 为什么在C++中,我必须强制转换来自malloc的返回值,但在C中不需要?

以下是在C++中有效的示例:

int *int_ptr = (int *)malloc(sizeof(int*));

以下是不使用强制转换的 C++ 示例,但无法正常工作:

int *int_ptr = malloc(sizeof(int*));

我听说在C语言中,实际上将malloc()的输出强制转换是个错误。

有人能对这个话题发表评论吗?


C++ 更加类型敏感,需要通过强制类型转换来指定精确的类型。 - Abhay
13
这与你的问题不是直接相关,但我认为你想要的是sizeof(int)而不是sizeof(int*)。话虽如此,最好使用sizeof *int_ptr,这可以确保你为指向的任何类型的 int_ptr 分配了正确的内存量。 - bcat
6
在C++中,为什么要使用malloc函数? - SoapBox
1
在C语言中,强制类型转换并不是错误,但完全没有必要。在C++中,除非使用专为C设计的接口,否则使用void*malloc()几乎肯定是一个错误。 - Mike Seymour
3
@R.. 去学习 D 或 Go 或其他类似的东西。 - Quonux
4个回答

42

几点需要注意:

C语言允许将空指针隐式转换为任何其他对象指针类型。C++不允许。

在C中对malloc()的结果进行强制转换将抑制有用的诊断,如果您忘记包含stdlib.h或其他没有声明malloc()的作用域,则会出现此问题。请记住,如果C看到一个函数调用而没有先前的声明,它将假定该函数返回int。如果您没有malloc()的声明并且省略了强制转换,您将得到一条有关尝试分配不兼容类型(int到指针)的诊断信息。如果强制转换结果,您将抑制诊断,并可能在运行时遇到问题,因为不能保证将指针值转换为int,再转回指针将给您一个有用的结果。

如果您正在编写C ++代码,则应该使用newdelete而不是malloc()free()。是的,是的,我听过所有人想要将其代码编译为C和C ++的原因,但是使用正确的内存管理工具来处理语言的好处优于维护两个版本的成本,在我看来。

注意:C89标准中添加了void *类型;早期版本的C将malloc()返回为char *,因此在这些版本中,如果要将结果分配给不同的指针类型,则需要强制转换。然而,几乎每个人都支持至少C89标准,因此您遇到这些旧实现的可能性非常低。


5
现代编译器是否会针对缺少malloc()声明发出警告,无论是否存在类型转换问题? - Daniel Stutzbach
@Daniel:这也取决于你的警告级别。强制转换警告通常会显示在比缺少声明更低的警告级别中。 - Mehrdad Afshari
也许是这样,但最好的做法还是不要强制转换类型。 - John Bode

14
那是因为C++是一种强类型语言。在C++中,只有“扩宽型”的隐式转换被允许,也就是说,新类型可以容纳旧类型所能容纳的每个值。从较小的整数类型向较大的整数类型转换是允许的;从任何指针类型到void*的转换都是允许的;从子类到其超类的转换也是允许的。所有其他转换都必须显式地进行,这样告诉编译器“我知道自己在做什么,这不是一个错误”。 malloc()返回一个void*,它可能是任何东西,因此编译器无法保证您的转换将成功(或有意义)。通过使用显式转换,您告诉编译器您正在执行的实际上是有意的。
相比之下,C没有如此严格的类型转换规则;您可以愉快地在任何两种类型之间进行转换,而你作为程序员需要负责确保没有发生任何坏事情。

6
我可以轻松地将“int”隐式转换为“bool”,没有问题。 - UncleBens
2
这是因为C++是一种强类型语言。而C不是吗? - cdhowie
2
C++是一种强类型语言。“强类型”这个术语几乎没有意义。作者通常用它来表示“我喜欢这种语言”。在C++中,只有当隐式转换是“扩大”的时候才允许它们,也就是说,如果新类型可以容纳旧类型可以容纳的每个值。这里有几个问题:一个“转换”是显式的类型转换;如果它是隐式的,那么它就不是转换。C++允许缩小类型转换,就像C一样:int i = 1.3; float f = ULONG_MAX;编译没有错误。将Derived*转换为Base*由于数组而不安全。C++允许它,C不允许。 - melpomene
1
在C语言中,你可以愉快地在任何两种类型之间进行强制类型转换。但这并不是完全正确的,例如你不能将其转换为结构体类型(无论是显式地(通过强制转换)还是隐式地)。 - melpomene

12

C语言支持将 void* 隐式转换为其他指针类型,而C++不允许这样做。

在C语言中,建议避免显式转换 malloc 返回值的类型,因为如果当前编译单元未包含 malloc 函数签名,编译器会假设其返回类型为 int,并将其隐式转换为你所分配的指针类型,从而导致编译时警告,提醒你立即解决该问题。如果进行显式转换,就算犯了这个错误,编译器也不会发出警告。


2

C语言的类型规则非常宽松,而C++则稍微严格一些。在这种情况下,区别在于C允许对象指针和void指针之间的隐式转换/赋值,而C++不允许。

实际上,旧式C甚至鼓励将对象指针隐式转换成/从void指针,作为旧式通用C编程的一部分。由于C++获得了函数重载和模板等功能,因此从未需要void指针。在C++中使用void指针通常是可疑的。

关于关于强制转换malloc结果会导致错误(如果没有包含stdlib.h),这个老生常谈的争论,这在过去21年里既不是有效的C++也不是有效的C。

最佳实践:

C

  • 如果您正在使用-std=c89-ansi-dinosaur等进行编译,则不要进行强制转换。
  • 否则,请遵循您的编码标准。
    • 如果它允许在void和对象指针之间进行隐式转换,则不要进行强制转换。
    • 如果它不允许,则进行强制转换(这可能意味着您正在使用静态代码分析)。
    • 如果您没有编码标准,那么这并不重要。强制转换是无害的,但会增加混乱。

C++

  • 始终进行强制转换。
  • 避免使用void指针。
  • 最重要的是,避免使用malloc,而改用new/new[]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接