【问题标题】:Why does C++ require a cast for malloc() but C doesn't?为什么 C++ 需要对 malloc() 进行强制转换,而 C 不需要?
【发布时间】:2021-03-19 17:01:09
【问题描述】:

我一直对此很好奇 - 为什么在 C++ 中我必须从 malloc 转换返回值而不是在 C 中?

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

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

这是 C++ 中不起作用的示例(无强制转换):

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

我听说在 C 中,事实上,从malloc() 转换输出是一个错误。

谁能评论这个话题?

【问题讨论】:

  • C++ 对类型更敏感要求您通过强制转换指定确切的类型。
  • 这与您的问题没有直接关系,但我认为您想要sizeof(int),而不是sizeof(int*)。也就是说,使用sizeof *int_ptr 会更好,这可以保证您为int_ptr 碰巧指向的任何类型分配正确的内存量。
  • 为什么要在 C++ 中使用 malloc?
  • 在 C 中,强制转换没有错,但完全没有必要。在 C++ 中,使用 void*malloc() 来处理任何事情(使用为 C 设计的接口除外)几乎肯定是错误的。
  • @R.. 去学习 D 或 Go 什么的

标签: c++ c malloc


【解决方案1】:

C 有非常宽松的类型规则,而 C++ 有更严格的规则。这种情况下的区别在于,C 允许在对象指针和void 指针之间进行隐式转换/赋值。 C++ 没有。

事实上,旧式 C 甚至鼓励与 void 指针的隐式转换,作为旧式通用 C 编程的一部分。 C++ 从来不需要 void 指针,因为它有函数重载和模板等。在 C++ 中使用 void 指针通常很可疑。

关于在不包括stdlib.h 的情况下消除关于强制转换malloc 导致错误的死马辩论,这样做从来都不是有效的C++,在过去的21 年里也不是有效的C。

最佳实践:

C

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

C++

  • 总是投射。
  • 避免使用void 指针。
  • 最重要的是,避免使用malloc 并改用new/new[]

【讨论】:

    【解决方案2】:

    几点:

    C 允许将 void 指针隐式转换为任何其他对象指针类型。 C++ 没有。

    如果您忘记包含 stdlib.h 或在范围内没有 malloc() 的声明,则在 C 中转换 malloc() 的结果将抑制有用的诊断。请记住,如果 C 看到没有事先声明的函数调用,它将假定该函数返回 int。如果您没有malloc() 的声明并且您放弃了演员表,您将得到一个诊断结果,表明您正在尝试分配不兼容的类型(int 到指针)。如果您转换结果,则会抑制诊断并且可能会出现运行时问题,因为不能保证将指针值转换为 int 并再次转换回指针会给您带来有用的结果。

    如果您正在编写 C++,则应该使用 newdelete 而不是 malloc()free()。是的,是的,是的,我听说过人们希望他们的代码同时编译为 C 和 C++ 的所有原因,但是为该语言使用正确的内存管理工具的好处超过了维护两个 IMO 版本的成本。

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

    【讨论】:

    • 无论转换问题如何,现代编译器都不会输出缺少 malloc() 声明的警告吗?
    • @Daniel:这也取决于您的警告级别。强制转换警告的警告级别通常低于缺少声明的警告级别。
    • 也许可以,但最好还是不要使用石膏。
    【解决方案3】:

    那是因为 C++ 是一种强类型语言。在 C++ 中,只有在“扩展”时才允许隐式转换,也就是说,如果新类型可以容纳旧类型可以容纳的每个值。允许从较小的整数类型转换为较大的整数类型;允许从任何指针类型转换为void*;允许从子类转换为其超类。所有其他类型的转换都必须显式进行,从而告诉编译器“我知道我在做什么,这不是错误”。

    malloc() 返回一个void*,它可以是任何东西,所以编译器不能保证你的转换会成功(或有意义)。通过使用显式强制转换,您是在告诉编译器您所做的实际上是有意的。

    C,OTOH,没有这么严格的铸造规则;您可以愉快地在任何两种类型之间进行转换,并且作为程序员,您有责任确保不会发生任何坏事。

    【讨论】:

    • 我可以毫无问题地将int 隐式转换为bool
    • “那是因为 C++ 是一种强类型语言。” ...而 C 不是!?
    • "C++ 是一种强类型语言。" 嗯。 “强类型”作为一个术语几乎没有意义。作者通常用它来表示“我喜欢这种语言”。 “在 C++ 中,隐式转换只有在“扩展”时才被允许,也就是说,如果新类型可以容纳旧类型可以容纳的每个值。” 这有几个问题:“强制转换” " 是显式类型转换;如果它是隐含的,则它不是演员表。 C++ 允许缩小类型转换,就像 C:int i = 1.3; float f = ULONG_MAX; 编译时没有错误一样。由于数组,将Derived* 转换为Base* 是不安全的。 C++ 允许,C 不允许。
    • "[在 C 中] 你可以愉快地在任意两种类型之间进行转换" 不正确,例如您不能转换为结构类型(无论是显式(通过强制转换)还是隐式)。
    【解决方案4】:

    C 支持从 void* 到其他指针类型的隐式转换。 C++ 不允许这样做。

    在 C 中不赞成显式转换 malloc 的返回值的一个原因是,如果当前编译单元中不包含 malloc 签名,编译器将假定返回类型为 int并将其隐式转换为您分配给的指针类型会导致您立即解决的编译时警告。使用显式强制转换,如果您犯了这个错误,将不会发出警告。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多