我应该投射 malloc 的结果吗?

Should I cast the result of malloc?

提问人:Patrick McDonald 提问时间:3/3/2009 最后编辑:Jan SchultkePatrick McDonald 更新时间:10/7/2023 访问量:376785

问:

在这个问题中,有人在评论中建议我不应该投出 .也就是说,我应该这样做:malloc

int *sieve = malloc(sizeof(*sieve) * length);

而不是:

int *sieve = (int *) malloc(sizeof(*sieve) * length);

为什么会这样?

C Malloc 铸造

评论

35赞 Flexo 1/16/2012
stackoverflow.com/q/7545365/168175
7赞 Hans Lepoeter 2/22/2021
演员是邪恶的。我看到很多代码被强制转换只是由于糟糕的编码实践。每当你需要插入一个时,你应该问自己的第一件事是“这里出了什么问题”。一切都按应有的方式宣布了吗?如果不是,则不需要铸造,因此会宣布某些错误。如果你真的需要对 int 左右的单个字节做一些低级的事情,请考虑使用联合来访问它们。这将宣布它们很好。根据经验,除非编译器抱怨,否则不要插入它们。然后避开它们。这个例子不会抱怨。void 指针将提升为任何类型。
2赞 An Ant 2/27/2021
@HansLepoeter在C++中,这些对于 malloc 来说是必要的,这为我的观点提供了一些基础,即它有问题
4赞 Braden Best 10/14/2022
@AnAnt C++不是 C。它们的类型系统完全不同。关于 C++ 类型系统的观察不一定适用于 C。事实上,他们很少这样做。
0赞 caulder 6/22/2023
你会考虑转换为基类(在 C 中)吗?

答:

107赞 EFraim 3/3/2009 #1

在 C 语言中,您可以获得从任何其他(数据)指针到任何其他(数据)指针的隐式转换。void *

评论

2赞 user3840170 11/20/2023
...因此?
0赞 Cœur 11/21/2023
这些信息已经包含在 unwind 的答案中。当然,它是在你发布 1 分钟后发布的,但给出了一个更清晰的答案和更高的分数,使你的答案没有额外的有用信息。
0赞 user16217248 11/21/2023
@C这仍然是一个答案。不是应该有 112 个赞成票的答案,但仍然是一个答案。
481赞 dirkgently 3/3/2009 #2

在 C 中,不需要强制转换 的返回值。返回的指向 void 的指针会自动转换为正确的类型。但是,如果您希望代码使用 C++ 编译器进行编译,则需要强制转换。社区中首选的替代方案是使用以下方法:mallocmalloc

int *sieve = malloc(sizeof *sieve * length);

此外,如果您更改了 .sieve

正如人们指出的那样,演员阵容很糟糕。尤其是指针投射。

评论

126赞 Michael Anderson 4/30/2015
@MAKZ我认为这让它看起来像是一个变量——所以我认为它更具可读性。malloc(length * sizeof *sieve)sizeofmalloc(length * sizeof(*sieve))
36赞 Toby Speight 8/20/2015
而且更具可读性。恕我直言。malloc(length * (sizeof *sieve))
25赞 chux - Reinstate Monica 12/11/2015
@Michael撇开安德森问题不谈,请注意,您建议的样式改变了顺序,考虑何时计算元素计数,在这种情况下保留第一个元素可以确保乘法至少用数学完成。 比较与。 - 第 2 个可能会溢出 当是较小的类型时。()length*widthsizeofsize_tmalloc(sizeof( *ptr) * length * width)malloc(length * width * sizeof (*ptr))length*widthwidth,lengthsize_t
3赞 Michael Anderson 12/11/2015
@chux这并不明显,但答案已经过编辑,因此我的评论不那么相关 - 最初的建议是malloc(sizeof *sieve * length)
20赞 David C. 2/13/2016
C 不是 C++。假装他们是最终会导致困惑和悲伤。如果您使用的是 C++,那么 C 样式的强制转换也很糟糕(除非您使用的是非常旧的 C++ 编译器)。并且(或)与C的任何方言都不兼容。static_cast>()reinterpret_cast<>()
2520赞 unwind 3/3/2009 #3

不;不应该强制转换结果,因为:

  • 这是不必要的,因为在这种情况下会自动安全地提升到任何其他指针类型。void *
  • 它给代码增加了混乱,强制转换不是很容易阅读(特别是如果指针类型很长)。
  • 它让你重复自己,这通常是不好的。
  • 如果您忘记包含 .这可能会导致崩溃(或者更糟糕的是,直到稍后在代码的某些完全不同的部分才导致崩溃)。考虑如果指针和整数的大小不同会发生什么;然后,您通过强制转换来隐藏警告,并且可能会丢失返回地址的部分内容。注意:从 C99 开始,隐式函数已从 C 中删除,这一点不再相关,因为没有自动假设未声明的函数返回 。<stdlib.h>int

澄清一下,请注意,我说的是“你不应该投射”,而不是“你不需要投射”。在我看来,即使你做对了,包括演员阵容也是一个错误。这样做根本没有好处,但有一堆潜在的风险,包括演员表明你不知道风险。

还要注意,正如评论者指出的那样,上面讨论的是直接 C,而不是 C++。我非常坚信 C 和 C++ 是独立的语言。


此外,您的代码会不必要地重复类型信息 (),这可能会导致错误。最好取消引用用于存储返回值的指针,将两者“锁定”在一起:int

int *sieve = malloc(length * sizeof *sieve);

有人可能会说:“好吧,以前类型是重复的,现在变量名是重复的;这不和以前一样重复吗?这怎么会更好呢?区别在于,如果有一天你更改了变量的类型,而忘记更改了要匹配下的类型,你会默默地得到一个错误大小的分配,并且没有警告;但是,如果您更改了变量的名称,但忘记更改 under 下的名称以匹配,则更有可能是旧名称不再解析为任何内容,因此您的代码将停止编译,提示您修复错误。sizeofsizeof

这也将 移到前面以增加可见性,并删除带有 ;仅当参数是类型名称时才需要它们。许多人似乎不知道(或忽略)这一点,这使得他们的代码更加冗长。记住:不是一个函数!:)lengthsizeofsizeof

虽然在极少数情况下移动到前面可能会增加可见性,但还应该注意,在一般情况下,最好将表达式写成:length

int *sieve = malloc(sizeof *sieve * length);

因为在这种情况下,保留第一个,确保乘法至少用数学完成。sizeofsize_t

比较: vs. 第二个可能溢出 when 和 是小于 的类型。malloc(sizeof *sieve * length * width)malloc(length * width * sizeof *sieve)length * widthwidthlengthsize_t

评论

36赞 n. m. could be an AI 12/8/2016
编译器已更改。最新的编译器会警告您缺少 malloc 的声明。
106赞 unwind 12/8/2016
@n.m. 好的。我认为假设任何阅读本文的人都有一个特定的编译器是很糟糕的。另外,由于 C11 的整个“隐式函数”概念都消失了,我不知道。不过,我看不出添加毫无意义的演员阵容有什么意义。你也只是为了把事情弄清楚吗?int x = (int) 12;
53赞 Braden Best 12/18/2016
@n.m. 如果显式转换一个无效指针“帮助”解决了一个错误,你更有可能遇到未定义的行为,这意味着有问题的程序可能有一个更糟糕的、未被发现的错误,你还没有遇到。有一天,在一个寒冷的冬夜,你下班回家,发现你的 GitHub 页面上充斥着问题报告,抱怨恶魔从用户的鼻子里飞出来
39赞 Amin Negm-Awad 1/8/2017
@unwind 即使我同意你的看法,也没有可比性。 是一个,演员根本什么也没做。的回退是 ,而不是强制转换为的指针类型。(如果不是.因此,类比将是没有人讨论的内容。(int)1212intmalloc()void *void *(int)12(void*)malloc(…)
12赞 P.P 1/18/2017
“我认为假设任何在这里阅读的人都有一个特定的编译器是很糟糕的。另外,自从 C11 以来,整个“隐式函数”概念都消失了,我不知道“——自 C99 以来它已经消失了(不仅仅是 C11)。如果未包含,则需要任何 C99 编译器才能发出诊断。在 4 个项目符号中,前 3 个是主观的(有足够的证据表明有些人倾向于在此页面中支持它),而第 4 个项目符号在此答案之前大约 10 年已在 C 语言中“修复”。虽然我不是在提倡支持演员阵容,但这里真的是用鼹鼠做一座山的案例。#include <stdlib.h>
118赞 pauljwilliams 3/3/2009 #4

在 C 语言中,可以将指针隐式转换为任何其他类型的指针,因此不需要强制转换。使用一个可能会向不经意的观察者暗示,需要一个是有原因的,这可能会产生误导。void

评论

0赞 FrankHB 5/13/2022
如果声明器中没有显式注释的类型,则强制转换通常更容易产生误导,因为它很容易混淆分配对象(对初始值不感兴趣)和仅分配一些(未初始化)内存的意图。
198赞 quinmars 3/3/2009 #5

正如其他人所说,它不是 C 需要的,但 C++ 是必需的。如果您认为要使用 C++ 编译器编译 C 代码,无论出于何种原因,您都可以改用宏,例如:

#ifdef __cplusplus
# define MALLOC(type) ((type *)malloc(sizeof(type)))
# define CALLOC(count, type) ((type *)calloc(count, sizeof(type)))
#else
# define MALLOC(type) (malloc(sizeof(type)))
# define CALLOC(count, type) (calloc(count, sizeof(type)))
#endif
# define FREE(pointer) free(pointer)

这样你仍然可以用非常紧凑的方式编写它:

int *sieve = MALLOC(int); // allocate single int => compare to stack int sieve = ???;
int *sieve_arr = CALLOC(4, int); // allocate 4 times size of int => compare to stack (int sieve_arr[4] = {0, 0, 0, 0};
// do something with the ptr or the value
FREE(sieve);
FREE(sieve_arr);

它将针对 C 和 C++ 进行编译。

评论

22赞 Hosam Aly 3/4/2009
既然你无论如何都在使用宏,你为什么不在 C++ 的定义中使用呢?new
78赞 quinmars 3/4/2009
因为没有理由这样做。它主要用于使用 C++ 编译器编译的 C 程序。如果你打算使用“new”,你得到的唯一就是问题。然后,您还需要一个免费的宏。你需要一个宏来释放一个数组,这是 C 语言中不存在的区别。
9赞 quinmars 3/4/2009
更不用说释放内存的不是你,而是你正在使用的 C 库,等等。许多可能的问题没有任何收获。
96赞 Graeme Perrow 7/17/2011
@Hosam:是的,确实如此。如果你使用,你必须使用,如果你使用,你必须你.切勿将它们混合使用。newdeletemalloc()free()
25赞 mah 4/16/2014
如果要采用这种方法,调用宏可能是一个坏主意,因为资源永远不会使用 (or ) 返回,所以你混合了你的词汇表。相反,命名它 ,或者更确切地说,在这种情况下,会更有意义。NEWdeleteDELETEMALLOCCALLOC
59赞 user968000 2/8/2013 #6

强制转换 的结果不是强制性的,因为它返回 ,并且 a 可以指向任何数据类型。mallocvoid*void*

评论

3赞 underscore_d 7/1/2020
事实并不能指出任何促成这一点的因素;事实上,A 可以隐式转换为任何其他指针类型。为了澄清区别,在 C++ 中,a 仍然可以指向任何内容,但隐式转换已被删除,因此必须强制转换。void*void*void*
407赞 Ron Burk 2/15/2013 #7

确实会投射,因为:

  • 它使你的代码在 C 和 C++ 之间更具可移植性,正如 SO 经验所表明的那样,许多程序员声称他们正在用 C 编写,而他们实际上是用 C++(或 C 加本地编译器扩展)编写的。
  • 如果不这样做,可能会隐藏一个错误:请注意所有混淆何时写入与 .type *type **
  • 它让你无法注意到你未能获得适当的头文件的想法错过了树木的森林。这就像说“不要担心你没有要求编译器抱怨没有看到原型的事实——讨厌的 stdlib.h 是真正需要记住的重要事情!#include
  • 它强制进行额外的认知交叉检查。它将(据称的)所需类型放在您正在为该变量的原始大小进行的算术运算旁边。我敢打赌,你可以做一个 SO 研究,表明当有演员表时,错误被捕获得更快。与断言一样,揭示意图的注释可以减少错误。malloc()
  • 以机器可以检查的方式重复自己通常是一个主意。事实上,这就是断言,而这种对 cast 的使用就是一种断言。断言仍然是我们获得正确代码的最通用技术,因为图灵在多年前就提出了这个想法。

评论

41赞 hyde 3/26/2013
@ulidtko 如果您不知道,可以编写编译为 C 和 C++ 的代码。事实上,大多数头文件都是这样的,它们通常包含代码(宏和内联函数)。将 / 文件编译为两者并不常见,但一种情况是在使用 C++ 编译器编译时添加 C++ 支持(但在使用 C 编译器或其他编译器时)。.c.cppthrowreturn -1;
43赞 paulm 5/7/2013
如果有人在标头中内联了 malloc 调用,我不会留下深刻的印象,#ifdef __cplusplus 和 extern “C” {} 用于这项工作,而不是添加额外的强制转换。
22赞 Elias Van Ootegem 12/23/2013
好吧,第 1 点无关紧要,因为 C != C++,如果您在调用中使用变量,其他点也是微不足道的: 如果完全证明:3 个指向 char 指针的指针。然后循环,并执行.分配 101 个字符的数组,整齐地初始化为零。无需石膏。就此而言,将声明更改为或任何其他类型,您仍然很好mallocchar **foo = malloc(3*sizeof(*foo));foo[i] = calloc(101, sizeof(*(foo[i])));unsigned char
42赞 DrBeco 9/26/2014
当我坚强地得到它时,它就来了!很棒的答案。这是我第一次在 StackOverflow 中 +1 两个相反的答案!+1 不,你不施法,+1 是的,你施法!哈哈。你们太棒了。对于我和我的学生,我下定决心:我做演员。学生在投掷时更容易发现学生所犯的错误。
21赞 supercat 9/19/2015
@Leushenko:以无法通过机器或本地检查验证的方式重复自己是不好的。以可以通过这种方式验证的方式重复自己并不那么糟糕。给定 ,malloc 无法避免重复有关 p 类型的信息,但如果一种类型发生了变化而另一种类型没有改变,编译器和本地代码检查都不会检测到任何问题。将代码更改为,如果强制转换类型不匹配,编译器将发出嘶吼声,本地检查将显示...struct Zebra *p; ... p=malloc(sizeof struct Zebra);p=(struct Zebra*)malloc(sizeof struct Zebra);p
32赞 swaps 4/27/2013 #8

返回的类型为 void*,可以将其转换为所需的数据指针类型,以便可取消引用。

评论

3赞 Toby Speight 8/20/2015
void* 可以转换为所需的类型,但无需这样做,因为它会自动转换。因此,演员阵容是不必要的,事实上,由于高分答案中提到的原因,这是不可取的。
1赞 Ferrarezi 1/8/2020
但只有当你需要“动态”取消引用它时,如果你创建一个变量,它将被安全、自动地转换为变量的有效类型,而无需强制转换(在 C 中)。
0赞 user3840170 9/6/2023
这如何以任何方式回答被问到的问题?
78赞 Yu Hao 6/10/2013 #9

现在没有必要强制转换返回的值,但我想补充一点,似乎没有人指出:malloc()

在古代,即在 ANSI C 提供指针的泛型类型之前,是此类用法的类型。在这种情况下,强制转换可以关闭编译器警告。void *char *

参考资料:C 常见问题解答

评论

5赞 Albert van der Horst 4/2/2016
关闭编译器警告是个坏主意。
12赞 Dan Bechard 4/12/2016
@AlbertvanderHorst 如果您通过解决确切的问题来这样做,则不会,警告会警告您。
1赞 Albert van der Horst 11/3/2016
@Dan .如果通过解决确切的问题意味着重写子程序以返回现代 ANSI C 类型而不是 char *,我同意。我不会称之为关闭编译器。不要屈服于那些坚持认为没有编译器警告的经理,而不是在每次重新编译时使用它们来查找可能的问题。Groetjes Albert
0赞 user3840170 9/9/2023
有多少人使用不提供 ANSI C 之前的编译器?void *
34赞 Jeyamaran 3/17/2014 #10

这取决于编程语言和编译器。如果您在 C 中使用,则无需键入 cast,因为它会自动键入 cast。但是,如果您使用的是 C++,那么您应该键入强制转换,因为将返回一个类型。mallocmallocvoid*

评论

4赞 August Karlstrom 9/5/2015
函数 malloc 在 C 中也返回一个 void 指针,但该语言的规则与 C++ 不同。
115赞 Lundin 3/20/2014 #11

您不会强制转换 的结果,因为这样做会给代码添加毫无意义的混乱。malloc

人们选择结果的最常见原因是因为他们不确定 C 语言是如何工作的。这是一个警告信号:如果你不知道特定的语言机制是如何工作的,那么就不要猜测。在 Stack Overflow 上查找或询问。malloc

一些评论:

  • void 指针可以转换为任何其他指针类型,而无需显式强制转换(C11、6.3.2.3 和 6.5.16.1)。

  • 但是,C++ 不允许在和另一个指针类型之间进行隐式转换。所以在 C++ 中,强制转换是正确的。但是,如果您使用 C++ 编程,则应使用 而不是 .而且你永远不应该使用 C++ 编译器编译 C 代码。void*newmalloc()

    如果需要使用相同的源代码同时支持 C 和 C++,请使用编译器开关来标记差异。不要尝试使用相同的代码来满足这两种语言标准,因为它们不兼容。

  • 如果 C 编译器找不到函数,因为您忘记包含标头,您将收到有关该函数的编译器/链接器错误。因此,如果您忘记包含这没什么大不了的,您将无法构建您的程序。<stdlib.h>

  • 在遵循超过 25 年历史的标准版本的古代编译器上,忘记包含会导致危险行为。因为在那个古老的标准中,没有可见原型的函数隐式地将返回类型转换为 。从显式转换结果将隐藏此错误。<stdlib.h>intmalloc

    但这确实不是问题。你没有使用一台有 25 年历史的计算机,那么你为什么要使用一台有 25 年历史的编译器呢?

评论

14赞 Don Hatch 11/2/2016
“毫无意义的杂乱无章”是一种不屑一顾的夸张,往往会破坏说服任何不同意你的人的可能性。演员当然不是毫无意义的;罗恩·伯克(Ron Burk)和卡兹(Kaz)的回答提出了我非常同意的赞成选角的论点。这些担忧是否比你提到的担忧更重要,这是一个合理的问题。对我来说,与他们相比,您的担忧看起来相对较小。
1赞 chux - Reinstate Monica 7/28/2017
6.3.2.3 不支持“void 指针可以在没有显式强制转换的情况下转换为任何其他指针类型”。也许您正在考虑“指向任何对象类型的指针”?“void pointer”和“pointer to a function”不是那么容易转换。
0赞 Lundin 4/12/2018
事实上,参考资料是不完整的。“隐式”的相关部分是简单赋值规则6.5.16.1。“一个操作数是指向对象类型的指针,另一个操作数是指向 void 的限定或非限定版本的指针”。为了完整起见,我已将此引用添加到答案中。
0赞 FrankHB 5/13/2022
正如我对另一个答案的评论,原因是通过滥用 C 语言规则来防止一些混淆。此外,如果没有 C 的对象创建的完整规则(包括有效类型的工作方式),就无法解决混淆,因此推理是相当不完整的。OTOH,源代码中的类似效果可以在 C++ 中通过带有成员的类类型在这里替换来实现,但由于规则更严格,C++ 仍然不会引起这种混淆。从这个意义上说,答案也是不完整的。template<T> operator T*() const {...}void*
0赞 Lundin 5/13/2022
@FrankHB 什么意思?有效类型不受强制转换的影响。返回的对象在写入之前不会获得有效类型(“左值访问”)。
61赞 user3079666 3/29/2014 #12

加上我学习计算机工程的经验,我看到我看到的两三位教授用 C 语言写作总是投 malloc,但是我问的那位(有大量的简历和对 C 的理解)告诉我,这是绝对不必要的,但只是用来绝对具体,并让学生进入绝对具体的心态。从本质上讲,强制转换不会改变它的工作方式,它完全按照它所说的去做,分配内存,并且强制转换不会影响它,你会得到相同的内存,即使你错误地将其强制转换为其他东西(并以某种方式避免编译器错误),C 也会以同样的方式访问它。

编辑:选角有一定的道理。当您使用数组表示法时,生成的代码必须知道它必须前进多少个内存位置才能到达下一个元素的开头,这是通过强制转换实现的。这样你就知道,对于 double,你领先 8 个字节,而对于 int,你领先 4 个字节,依此类推。因此,如果您使用指针表示法,则它不起作用,在数组表示法中,它变得必要。

评论

4赞 Lundin 5/27/2014
除非如前所述,强制转换可能会隐藏错误,并使编译器或静态分析器更难分析代码。
3赞 chux - Reinstate Monica 8/24/2014
“从本质上讲,选角不会改变它的工作方式”。转换为匹配类型不应更改任何内容,但是如果 var 的类型更改并且强制转换不再匹配,会出现问题吗?IWO、铸件和变型应保持同步 - 维护工作量的两倍。
3赞 chux - Reinstate Monica 7/28/2017
我明白为什么教授们更喜欢选角了。从教育的角度来看,投射可能很有用,因为它向教师传达了信息,并且不需要维护学生代码 - 其丢弃代码。然而,从编码、同行评审和维护的角度来看,它是如此简单和更好。p = malloc(sizeof *p * n);
40赞 Endeavour 7/13/2014 #13

void 指针是一个泛型对象指针,C 支持从 void 指针类型到其他类型的隐式转换,因此不需要显式类型转换它。

但是,如果您希望相同的代码在不支持隐式转换的 C++ 平台上完美兼容,则需要进行类型转换,因此这完全取决于可用性。

评论

3赞 Toby Speight 8/20/2015
将单个源代码编译为 C 和 C++ 并不是一个正常的用例(例如,与使用包含声明的头文件将 C 和 C++ 代码链接在一起相反)。在 C++ 中使用 and 朋友是一个很好的警告信号,它值得特别关注(或用 C 重写)。malloc
16赞 user877329 6/12/2015 #14

尽可能用 C 语言编程时,最好的办法是:

  1. 使程序通过 C 编译器编译,并打开所有警告并修复所有错误和警告-Wall
  2. 确保没有声明为auto
  3. 然后使用 C++ 编译器和 进行编译。修复所有错误和警告。-Wall-std=c++11
  4. 现在再次使用 C 编译器进行编译。您的程序现在应该在没有任何警告的情况下编译,并且包含更少的错误。

此过程允许您利用 C++ 严格的类型检查,从而减少 bug 的数量。特别是,此过程会强制您包含,否则您将得到stdlib.h

malloc未在此范围内声明

并且还迫使你投射结果,否则你会得到malloc

从 到 的转换无效void*T*

或者您的目标类型是什么。

我能找到用 C 而不是 C++ 编写的唯一好处是

  1. C 具有明确指定的 ABI
  2. C++ 可能会生成更多代码 [异常、RTTI、模板、运行时多态性]

请注意,在理想情况下,当将 C 共有的子集与静态多态特征一起使用时,第二个缺点应该消失。

对于那些觉得 C++ 严格规则不方便的人,我们可以使用具有推断类型的 C++11 功能

auto memblock=static_cast<T*>(malloc(n*sizeof(T))); //Mult may overflow...

评论

23赞 Toby Speight 6/26/2015
将 C 编译器用于 C 代码。将 C++ 编译器用于 C++ 代码。没有如果,没有但是。用 C++ 重写 C 代码完全是另一回事,可能值得也可能不值得花时间和风险。
4赞 autistic 12/8/2015
我想补充@TobySpeight建议:如果你需要在C++项目中使用 C 代码,你通常可以将 C 代码编译为 C(例如),将 C++ 代码编译为 C++(例如),然后将它们链接在一起(例如 反之亦然,具体取决于项目依赖项)。现在应该没有理由剥夺自己任何一种语言的任何美好功能......gcc -c c_code.cg++ -c cpp_code.cppgcc c_code.o cpp_code.o
1赞 autistic 12/8/2015
@user877329 这是一个更明智的选择,而不是为了“C++兼容”而煞费苦心地向代码添加强制转换,从而降低代码的可读性。
1赞 Peter Cordes 10/24/2016
与 C++ 相比,C 的其他优点:C99 可变长度数组,用于非常有效地分配/释放暂存空间。当你无意中写出非常量初始化器时,你不能不小心写出非常量初始化器(例如,如果你认为你很聪明,把它放在全局范围内,这样多个函数就可以共享一个常量,那么构造函数在 C 中不是一回事这一事实会阻止你生成更糟糕的代码。(这真的是找到了 C 限制的一线希望......static const __m128 ones = _mm_set1_ps(1.0f);
1赞 Peter Cordes 10/24/2016
在这种情况下,可能主要优点是 C 允许您编写 ,如果更改为不同的类型名称,则首先不需要更改。强制转换的“优点”是,如果类型错误,则会出现编译错误,但如果它正常工作,那就更好了。p = malloc(sizeof(*p));pp
9赞 iec2011007 7/29/2015 #15

void 指针背后的概念是它可以被强制转换为任何数据类型,这就是 malloc 返回 void 的原因。此外,您还必须了解自动类型转换。因此,尽管您必须这样做,但强制要求投指针并不是强制性的。它有助于保持代码整洁并帮助调试

评论

15赞 Toby Speight 8/20/2015
"这不是强制性的——尽管你必须这样做“——我认为这里有一个矛盾!
10赞 Bill Woodger 9/8/2015
我认为你应该把这篇文章读给某人听,看看他们是否理解你想说什么。然后重写它,明确你想说什么。我真的不明白你的答案是什么。
32赞 August Karlstrom 9/4/2015 #16

在 C 语言中,void 指针可以分配给任何指针,这就是为什么不应使用类型转换的原因。如果你想要“类型安全”的分配,我可以推荐以下宏函数,我总是在我的 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++) {
   ...
}

评论

2赞 chux - Reinstate Monica 7/28/2017
“void 指针可以分配给任何对象指针” 函数指针是另一个问题,尽管不是问题。malloc()
1赞 chux - Reinstate Monica 12/27/2017
在这些情况下,分配到/从函数指针分配指针可能会丢失信息,因此“可以将空指针分配给任何指针”是一个问题。不过,将 、 from 分配给任何对象指针都不是问题。void*void*malloc()
14赞 user3949394 9/10/2015 #17

强制转换仅适用于C++C.In 如果您使用的是 C++ 编译器,最好将其更改为 C 编译器。

44赞 Slothworks 10/10/2015 #18

《GNU C 库参考手册》是这么说的:

您可以将结果存储到任何指针变量中,而无需 强制转换,因为 ISO C 会自动将类型转换为另一种类型 必要时的指针类型。但是演员阵容在上下文中是必要的 除赋值运算符外,或者您可能希望代码运行。 在传统 C 中。mallocvoid *

事实上,ISO C11标准(p347)是这样说的:

如果分配成功,则返回的指针会适当地对齐,以便 它可以被分配给指向任何类型的对象的指针,该指针具有 基本对齐要求,然后用于访问这样的 对象或分配的空间中此类对象的数组(直到 空间被显式解除分配)

174赞 ashiquzzaman33 10/10/2015 #19

来自维基百科

铸造优势

  • 包括强制转换可能允许 C 程序或函数编译为 C++。

  • 强制转换允许 1989 年之前的 malloc 版本,该版本最初返回 char *。

  • 如果目标指针类型发生更改,强制转换可以帮助开发人员识别类型大小的不一致,特别是当指针声明远离 malloc() 调用时(尽管现代编译器和静态分析器可以在不需要强制转换的情况下警告此类行为)。

铸造的缺点

  • 在 ANSI C 标准下,强制转换是多余的。

  • 添加强制转换可能会掩盖在 找到了 malloc 的原型。在没有 prototype for malloc,标准要求 C 编译器 假设 malloc 返回一个 int。如果没有强制转换,则会发出警告 当此整数分配给指针时发出;但是,随着 投射,此警告不产生,隐藏错误。在某些 体系结构和数据模型(例如 64 位系统上的 LP64,其中 long 和指针是 64 位,int 是 32 位),此错误可以 实际上会导致未定义的行为,正如隐式声明的那样 malloc 返回一个 32 位值,而实际定义的函数 返回一个 64 位值。取决于调用约定和内存 布局,这可能会导致堆栈粉碎。此问题不太可能发生 在现代编译器中被忽视,因为它们统一生成 警告已使用未声明的函数,因此警告将 仍然出现。例如,GCC 的默认行为是显示 显示“内置的不兼容隐式声明”的警告 函数“,无论是否存在强制转换。

  • 如果指针的类型在其声明时发生更改,则可以 此外,需要更改调用和转换 malloc 的所有行。

尽管不强制转换的 malloc 是首选方法,并且大多数有经验的程序员都选择它,但您应该使用任何您喜欢的方法,以了解这些问题。

即:如果需要将C程序编译为C++(尽管它是一门单独的语言),则必须转换使用结果。malloc

评论

3赞 Spikatrix 5/14/2016
如果目标指针类型发生变化,特别是如果指针声明远离 malloc() 调用,则强制转换可以帮助开发人员识别类型大小的不一致”是什么意思?你能举个例子吗?
5赞 Peter Cordes 10/24/2016
@CoolGuy:请参阅之前对另一个答案的评论。但请注意,该成语会自动获取类型的更改,因此您不必收到警告并更改任何内容。因此,与非铸造的最佳替代方案相比,这不是一个真正的优势。p = malloc(sizeof(*p) * count)
11赞 Peter - Reinstate Monica 11/16/2016
这是正确的答案:有利有弊,归根结底是品味问题(除非代码必须编译为 C++ - 那么强制转换是强制性的)。
4赞 Michaël Roy 6/18/2017
第 3 点是没有意义的,因为如果指针的类型在其声明时发生了变化,则应检查该类型的 malloc、realloc 和 free 的每个实例。选角会迫使你这样做。
1赞 SO_fix_the_vote_sorting_bug 8/7/2021
如果忘记包含 stdlib.h,并且程序编译,那么如果没有 malloc 的定义,它如何链接?如果它仍然链接并运行,那么对于任何给定的 CPU,哪些指令实际上会在那行上运行?我想我应该检查一下 godbolt...
24赞 StephenG - Help Ukraine 12/5/2015 #20

习惯了 GCC 和 Clang 的人被宠坏了。外面的情况并不好。

多年来,我一直对被要求使用的老化编译器感到非常震惊。通常,公司和经理会采用一种极端保守的方法来改变编译器,甚至不会测试新的编译器(具有更好的标准合规性和代码优化)是否会在他们的系统中工作。对于在职开发人员来说,实际的现实是,当你编写代码时,你需要覆盖你的基础,不幸的是,如果你无法控制什么编译器可以应用于你的代码,那么强制转换mallocs是一个好习惯。

我还建议许多组织应用他们自己的编码标准,如果定义了它,这应该是人们遵循的方法。在没有明确指导的情况下,我倾向于选择最有可能到处编译,而不是盲目地遵守标准。

在现行标准下没有必要的论点是相当有效的。但这种说法忽略了现实世界的实用性。我们不是在一个完全由当今标准统治的世界里编码,而是在我喜欢称之为“本地管理的现实领域”的实用性中编码。这比时空更弯曲和扭曲。:-)

YMMV。

我倾向于认为施放 malloc 是一种防御行动。不漂亮,不完美,但总体上是安全的。(老实说,如果你没有包括 stdlib.h,那么你遇到的问题比投射 malloc 要多得多

18赞 Kaz 3/30/2016 #21

我加入强制转换只是为了表示对类型系统中丑陋漏洞的不赞成,它允许像以下代码片段这样的代码在没有诊断的情况下进行编译,即使没有使用强制转换来带来错误的转换:

double d;
void *p = &d;
int *q = p;

我希望它不存在(而且它在 C++ 中不存在),所以我投了。它代表了我的品味,以及我的编程政治。我不仅在投指针,而且有效地投了一张选票,赶走了愚蠢的恶魔。如果我真的不能摆脱愚蠢,那么至少让我用抗议的姿态来表达这样做的愿望。

事实上,一个好的做法是用返回的函数包装(和朋友),基本上永远不要在代码中使用。如果需要指向任何对象的通用指针,请使用 或 ,并在两个方向上进行强制转换。也许,一种可以放纵的放松是使用类似石膏和不使用石膏的功能。mallocunsigned char *void *char *unsigned char *memsetmemcpy

关于转换和 C++ 兼容性的主题,如果您编写代码以便它编译为 C 和 C++(在这种情况下,您必须在将其分配给其他东西时转换返回值 ),您可以为自己做一件非常有用的事情:您可以使用宏进行转换,在编译为 C++ 时转换为 C++ 样式的转换, 但在编译为 C 时简化为 C 强制转换:mallocvoid *

/* In a header somewhere */
#ifdef __cplusplus
#define strip_qual(TYPE, EXPR) (const_cast<TYPE>(EXPR))
#define convert(TYPE, EXPR) (static_cast<TYPE>(EXPR))
#define coerce(TYPE, EXPR) (reinterpret_cast<TYPE>(EXPR))
#else
#define strip_qual(TYPE, EXPR) ((TYPE) (EXPR))
#define convert(TYPE, EXPR) ((TYPE) (EXPR))
#define coerce(TYPE, EXPR) ((TYPE) (EXPR))
#endif

如果您遵循这些宏,那么在代码库中搜索这些标识符将向您显示所有强制转换的位置,以便您可以查看其中是否有任何不正确。grep

然后,如果您定期使用 C++ 编译代码,它将强制使用适当的强制转换。例如,如果您只使用 删除 或 ,但程序以现在涉及类型转换的方式更改,您将获得诊断,并且您必须使用强制转换的组合来获得所需的转换。strip_qualconstvolatile

为了帮助您遵守这些宏,GNU C++(不是 C!)编译器有一个漂亮的功能:为所有出现的 C 样式强制转换生成可选的诊断。

     -Wold-style-cast (C++ and Objective-C++ only)
         Warn if an old-style (C-style) cast to a non-void type is used
         within a C++ program.  The new-style casts (dynamic_cast,
         static_cast, reinterpret_cast, and const_cast) are less vulnerable
         to unintended effects and much easier to search for.

如果 C 代码编译为 C++,则可以使用此选项找出可能潜入代码的所有强制转换语法,并通过将其替换为上述宏中的适当选择(或组合,如有必要)来跟进这些诊断。-Wold-style-cast(type)

这种转换处理是在“干净的 C”中工作的最大的独立技术理由:结合的 C 和 C++ 方言,这反过来又在技术上证明了转换 的返回值是合理的。malloc

评论

0赞 Phil1970 6/10/2016
正如其他人指出的那样,我通常建议不要混合使用 C 和 C++ 代码。但是,如果您有充分的理由这样做,那么宏可能会很有用。
0赞 Kaz 6/11/2016
@Phil1970 它都是用一种有凝聚力的方言编写的,这种方言恰好可以移植到 C 和 C++ 编译器,并利用了 C++ 的一些功能。它必须全部编译为 C++,否则全部编译为 C。
0赞 Kaz 6/15/2016
也就是说,我在之前的评论中想说的是,没有混合使用C和C++。目的是代码全部编译为 C 或全部编译为 C++。
17赞 proski 6/29/2016 #22

我更喜欢做演员,但不是手动。我最喜欢的是使用 glib 中的宏。如果不使用 glib,我会添加类似的宏。这些宏在不影响类型安全性的情况下减少了代码重复。如果类型错误,则会在非 void 指针之间进行隐式强制转换,这将导致警告(C++ 中的错误)。如果忘记包含定义 和 的标头,则会出现错误。 两者都采用相同的参数,不像 .只需添加即可获得零初始化内存。代码可以使用 C++ 编译器进行编译,无需更改。g_newg_new0g_newg_new0g_newg_new0malloccalloc0

10赞 dhana govindarajan 7/18/2016 #23

void 指针是一个泛型指针,C 支持从 void 指针类型到其他类型的隐式转换,因此不需要显式类型转换它。

但是,如果您希望相同的代码在不支持隐式转换的 C++ 平台上完美兼容,则需要进行类型转换,因此这完全取决于可用性。

10赞 Mohit 11/8/2016 #24
  1. 如前所述,C不需要它,但C++需要它。

  2. 包括强制转换可能允许 C 程序或函数编译为 C++。

  3. 在 C 中,这是不必要的,因为 void * 会自动安全地提升到任何其他指针类型。

  4. 但是,如果您当时强制转换,如果您忘记包含 stdlib.h,它可能会隐藏错误。这可能会导致崩溃(或者更糟糕的是,不会导致崩溃 直到稍后在代码的一些完全不同的部分)。

    因为 stdlib.h 包含 malloc 的原型。在 由于没有 malloc 的原型,该标准要求 C 编译器假定 malloc 返回一个 int。如果没有强制转换,则 当此整数分配给指针时发出警告; 但是,在强制转换时,不会产生此警告,从而隐藏了一个错误。

21赞 user2371524 8/16/2017 #25

不,您不会强制转换 的结果。malloc()

通常,您不会向 void * 强制转换或从 void * 强制转换

不这样做的一个典型原因是,如果不这样做,可能会被忽视。这在很长一段时间内不再是问题,因为 C99 使隐式函数声明成为非法,因此如果您的编译器至少符合 C99,您将收到一条诊断消息。#include <stdlib.h>

但是,有一个更充分的理由不引入不必要的指针转换:

在 C 语言中,指针转换几乎总是一个错误。这是因为以下规则(N1570 中 §6.5 p7,C11 的最新草案):

对象的存储值只能由具有 以下类型:
— 与对象的有效类型兼容的类型, — 与对象的有效类型兼容的类型的限定版本,

— 与对象的有效类型对应的有符号或无符号类型 object, — 一种类型,
该类型是与 对象的有效类型,— 一种聚合或联合类型,
其类型包括上述类型之一 成员(递归地包括子聚合或包含的联合的成员),或者
— 字符类型。

这也称为严格锯齿规则。因此,以下代码是未定义的行为

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++ 中,与 和 from 的转换不是隐式的,这是有道理的。C++ 有一整套不同风格的强制转换。void *

评论

1赞 0___________ 8/23/2017
在您的示例中,您避免了 void *。从 double * 到 int * 的强制转换是有区别的,反之亦然。malloc 返回与最大标准类型对齐的 pointel,因此即使有人将此对齐指针强制转换为其他类型,也不会破坏别名规则。
0赞 8/23/2017
混叠与对齐完全无关,对于您评论的其余部分 - 您显然没有明白重点。
0赞 8/23/2017
@PeterJ:以防万一,重点是避免不必要的指针投射,所以它看起来不像是一段你必须特别注意的代码。
0赞 Lundin 8/23/2017
严格的别名问题实际上与无效指针没有任何关系。为了获得由严格别名冲突导致的错误,必须取消引用指向的数据。由于您无法取消引用 void 指针,因此根据定义,此类 bug 与 void 指针无关,而是与其他内容相关。
0赞 Lundin 8/23/2017
相反,您必须制定规则来禁止所有指针投射。但是,您将如何编写诸如序列化例程和硬件相关编程之类的东西呢?这是 C 的强项。如果您知道自己在做什么,这样的演员阵容很好。
13赞 Aashish Kumar 10/3/2017 #26

malloc 的强制转换在 C 中是不必要的,但在 C++ 中是强制性的。

在 C 中不需要强制转换,因为:

  • void *在 C 的情况下,会自动安全地提升为任何其他指针类型。
  • 如果您忘记包含 .这可能会导致崩溃。<stdlib.h>
  • 如果指针和整数的大小不同,则会通过强制转换来隐藏警告,并且可能会丢失返回地址的位。
  • 如果指针的类型在其声明时发生了变化,则可能还需要更改调用和强制转换的所有行。malloc

另一方面,强制转换可能会增加程序的可移植性。即,它允许 C 程序或函数编译为 C++。

1赞 pasignature 3/5/2020 #27

对我来说,这里的结论是完全没有必要用 C 语言进行投射,但如果你无论如何投射,它不会影响,因为仍然会为你分配你所要求的祝福内存空间。 另一个带回家的是人们进行强制转换的原因或原因之一,这是为了使他们能够用 C 或 C++ 编译相同的程序。mallocmallocmalloc

可能还有其他原因,但几乎可以肯定的是,其他原因迟早会让你陷入严重的麻烦。

26赞 RobertS supports Monica Cellio 6/13/2020 #28

这个问题是基于意见的滥用的主题。

有时我注意到这样的评论:

不要投射 malloc 的结果

为什么不投射 malloc 的结果

关于OP使用铸造的问题。评论本身包含指向此问题的超链接。

在任何可能的方式上都是不恰当和不正确的。当它真正取决于自己的编码风格时,没有对错。


为什么会这样?

它基于两个原因:

  1. 这个问题确实是基于意见的。从技术上讲,这个问题应该在几年前就以意见为基础。一个“我该做”或“我不要”或等效我应该”或“我不应该”的问题,如果没有自己意见的态度,你就无法集中回答。关闭问题的原因之一是因为它“可能会导致基于意见的答案”,正如这里所展示的那样。

  2. 许多答案(包括明显和最被接受的@unwind答案)要么完全或几乎完全基于意见(例如,如果你进行强制转换或重复,就会将神秘的“混乱”添加到你的代码中,这将是不好的),并且表现出一种明确而集中的倾向,即省略强制转换。他们一方面争论演员的冗余,但更糟糕的是,他们争论解决由编程本身的错误/失败引起的错误 - 如果想使用 .#include <stdlib.h>malloc()


我想对所讨论的一些观点提出一个真实的看法,而不是我个人的看法。有几点需要特别注意:

  1. 这样一个非常容易陷入自己观点的问题需要一个中立的利弊的答案。不仅是缺点或优点。

    此答案中列出了优缺点的良好概述:

    https://stackoverflow.com/a/33047365/12139179

    (我个人认为这是迄今为止最好的答案,因为这个原因。


  1. 最多会遇到一个原因来解释演员的遗漏,因为演员可能隐藏了一个错误。

    如果有人使用隐式声明,则返回(隐式函数自 C99 以来已从标准中消失)和 ,如本问题所示malloc()intsizeof(int) != sizeof(int*)

    为什么此代码在 64 位架构上出现段错误,但在 32 位架构上工作正常?

    演员会隐藏一个错误。

    虽然这是真的,但它只显示了故事的一半,因为演员阵容的省略只会是一个更大的错误的前瞻性解决方案——不包括在使用 .stdlib.hmalloc()

    这永远不会是一个严重的问题,如果你,

    1. 使用符合 C99 或更高版本的编译器(推荐使用,并且应该是强制性的),并且

    2. 当您想在代码中使用时,不要忘记包含,这本身就是一个巨大的错误。stdlib.hmalloc()


  1. 有些人争论 C 代码的 C++ 合规性,因为强制转换在 C++ 中是强制性的。

    首先要说的是:使用 C++ 编译器编译 C 代码不是一个好的做法。

    C和C++实际上是两种完全不同的语言,具有不同的语义。

    但是,如果您真的想要/需要使 C 代码符合 C++,反之亦然,请使用编译器开关而不是任何强制转换。

    由于演员表倾向于被宣布为多余甚至有害,我想关注这些问题,这些问题给出了为什么演员表有用甚至必要的充分理由:


  1. 当代码(分别是分配的指针的类型(以及强制转换的类型))发生更改时,强制转换可能是无益的,尽管在大多数情况下这不太可能。然后,您还需要维护/更改所有强制转换,如果您在代码中对内存管理函数进行了几千次调用,这确实可以总结并降低维护效率。

总结:

事实是,如果分配的指针指向具有基本对齐要求的对象(包括所有对象中的大多数),则根据 C 标准(自 ANSI-C (C89/C90) 以来),强制转换是多余的。

在这种情况下,您不需要进行强制转换,因为指针会自动对齐:

“未指定通过连续调用 aligned_alloc、calloc、malloc 和 realloc 函数分配的存储顺序和连续性。如果分配成功,则返回的指针会适当地对齐,以便可以将其分配给指向具有基本对齐要求的任何类型的对象的指针,然后用于访问此类对象或分配的空间中的此类对象的数组(直到显式解除分配空间)。

来源:C18, §7.22.3/1


“基本对齐是小于或等于的有效对齐。所有存储持续时间的对象的实现应支持基本对齐。以下类型的对齐要求应为基本对齐:_Alignof (max_align_t)

— 所有原子、合格或不合格的基本类型;

— 所有原子、限定或非限定的枚举类型;

— 所有原子指针、合格指针或非限定指针类型;

— 元素类型具有基本对齐要求的所有数组类型;77 千米赛

— 第 7 条中指定为完整对象类型的所有类型;

- 所有结构或并集类型:其所有元素都具有具有基本对齐要求的类型,并且其元素均未具有指定非基本对齐的对齐说明符。

  1. 如 6.2.1 所述,后面的声明可能会隐藏前面的声明。

来源:C18, §6.2.8/2

但是,如果为具有扩展对齐要求的实现定义的对象分配内存,则需要强制转换。

扩展对齐方式由大于 的对齐方式表示。它由实现定义是否支持任何扩展对齐方式以及支持这些对齐方式的存储持续时间。具有扩展对齐要求的类型是过度对齐类型。58)_Alignof (max_align_t)

源。C18,§6.2.8/3

其他一切都取决于具体用例和自己的意见。

请注意您的教育方式。

我建议你先仔细阅读到目前为止所做的所有答案(以及他们可能指向失败的评论),然后建立你自己的观点,如果你或如果你没有在特定案例中投出结果。malloc()

请注意:

这个问题没有正确和错误的答案。这是一个风格问题,你自己决定你选择哪种方式(当然,如果你不是被教育或工作强迫的话)。请注意这一点,不要让欺骗您


最后一点:我最近投票决定将这个问题作为基于意见的问题,这确实是多年来需要的。如果您获得了关闭/重新打开的特权,我也想邀请您这样做。

评论

2赞 Lundin 6/18/2020
不过,这与这个旧答案中所说的几乎相同:stackoverflow.com/a/22538350/584518
1赞 Ctx 6/18/2020
@Lundin 你一定是贴错了链接,这个答案与这个完全无关
1赞 Lundin 6/18/2020
@RobertSsupportsMonicaCellio 那么,你会怎么称呼这个表达中的演员?主观编码风格的问题?int x, y; x = (int)y;
5赞 Konrad Rudolph 7/29/2020
这是一个糟糕的答案,因为它依赖于一个隐含的主张,即这场辩论中的所有论点都具有同等价值,而事实显然并非如此。出于各种原因(从主观到事实错误),支持演员的论点——除了一个利基例外(遵守外部代码风格要求)——只是糟糕的论点。仅仅因为双方有名义上的“论点”,就得出结论是错误的,因此决定是折腾的,或者是基于意见的。同样,你会站在关于生物进化或全球变暖的非科学辩论的两边。
4赞 RobertS supports Monica Cellio 8/3/2020
@KonradRudolph我不明白支持省略演员的基于意见的论点如何比关于它被允许和可以使用的论点更有价值,我也不明白为什么所有给定的选角论点都是“”论点。“”的分类也是主观的和基于意见的,我想用这个答案来防止,只是简单的事实。
4赞 tstanisl 1/17/2022 #29

主要问题是获得合适的尺寸malloc

返回的内存形式是非类型化的,并且由于简单的强制转换,它不会神奇地获得有效的类型malloc()

我想这两种方法都很好,选择应该取决于程序员的意图。

  1. 如果为某个类型分配内存,则使用强制转换。

ptr = (T*)malloc(sizeof(T));

  1. 如果为给定指针分配内存,则不要使用强制转换。

ptr = malloc(sizeof *ptr);

广告 1

第一种方法通过为给定类型分配内存,然后强制转换内存以确保将其分配给正确的指针来确保大小正确。如果使用了不正确的类型,则编译器将发出警告/错误。如果类型发生更改,则编译器将指出代码需要重构的位置。ptrptr

此外,第一种方法可以组合成一个类似于 C++ 运算符的宏。new

#define NEW(T) ((T*)malloc(sizeof(T)))
...
ptr = NEW(T);

此外,如果 是 ,则此方法有效。ptrvoid*

广告 2

第二种方法不关心类型,它通过从指针的类型中获取大小来确保正确的大小。这种方法的主要优点是每当类型发生变化时都会自动调整存储大小。 它可以在重构时节省一些时间(或错误)。ptr

缺点是该方法不起作用,但如果是,但它可能被认为是一件好事。并且它不适用于 C++,因此不应在 C++ 程序将使用的标头中的内联函数中使用。ptrvoid*

就个人而言,我更喜欢第二种选择。