2650

这个问题中,有人在评论中建议我不应该转换结果malloc。即,我应该这样做:

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

而不是:

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

为什么会这样?

4

29 回答 29

2415

TL;博士

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

有两个问题。强制转换并且您使用类型而不是变量作为 sizeof 的参数。相反,这样做:

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

长版

没有;你投射结果,因为:

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

于 2009-03-03T10:17:53.817 回答
435

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

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

如果您更改sieve.

正如人们指出的那样,演员阵容很糟糕。特别是指针转换。

于 2009-03-03T10:17:21.433 回答
386

确实投了,因为:

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

正如其他人所说,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++ 编译。

于 2009-03-03T11:17:46.327 回答
160

来自维基百科

铸造的优势

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

  • 演员表允许最初返回 char * 的 malloc 的 1989 之前版本。

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

铸造的缺点

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

  • 添加强制转换可能会掩盖包含标头stdlib.h的失败,其中找到了 malloc 的原型。在没有 malloc 原型的情况下,标准要求 C 编译器假定 malloc 返回一个 int。如果没有强制转换,则在将此整数分配给指针时发出警告;但是,使用演员表时,不会产生此警告,从而隐藏了一个错误。在某些架构和数据模型上(例如 64 位系统上的 LP64,其中 long 和指针是 64 位而 int 是 32 位),此错误实际上可能导致未定义的行为,因为隐式声明的 malloc 返回一个 32-位值,而实际定义的函数返回一个 64 位值。根据调用约定和内存布局,这可能会导致堆栈粉碎。这个问题在现代编译器中不太可能被忽视,因为他们统一产生一个未声明的函数已被使用的警告,所以仍然会出现一个警告。例如,GCC 的默认行为是显示一条警告,内容为“内置函数的不兼容隐式声明”,无论是否存在强制转换。

  • 如果指针的类型在其声明时发生更改,则可能还需要更改调用 malloc 并强制转换的所有行。

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

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

于 2015-10-09T21:23:21.457 回答
113

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

于 2009-03-03T10:18:12.710 回答
110

您不会强制转换 的结果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 年的编译器呢?

于 2014-03-20T15:53:14.890 回答
101

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

于 2009-03-03T10:16:21.467 回答
75

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

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

参考:C 常见问题

于 2013-06-09T17:31:35.053 回答
57

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

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

于 2014-03-28T18:21:31.837 回答
56

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

于 2013-02-07T22:22:34.110 回答
40

这就是GNU C 库参考手册所说的:

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

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

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

于 2015-10-09T17:47:38.610 回答
36

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

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

于 2014-07-13T06:42:25.510 回答
31

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

于 2013-04-26T16:43:31.443 回答
31

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

于 2014-03-17T13:16:41.423 回答
30

在 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++) {
   ...
}
于 2015-09-04T11:52:04.793 回答
21

习惯 GCC 和 Clang 的人都被宠坏了。那里并不是那么好。

多年来,我被要求使用的年代久远的编译器吓坏了。公司和管理人员通常会采用极其保守的方法来更改编译器,甚至不会测试新的编译器(具有更好的标准合规性和代码优化)是否可以在他们的系统中工作。工作开发人员的实际情况是,当您编写代码时,您需要覆盖您的基础,不幸的是,如果您无法控制可以将哪些编译器应用于您的代码,那么强制转换 malloc 是一个好习惯。

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

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

YMMV。

我倾向于将 malloc 转换为防御性操作。不漂亮,不完美,但通常是安全的。(老实说,如果你没有包含 stdlib.h 那么你强制转换 malloc 有更多的问题!)。

于 2015-12-04T17:27:54.660 回答
20

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

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

不要转换 malloc 的结果

或者

为什么你不投射 malloc 的结果

关于 OP 使用强制转换的问题。评论本身包含指向此问题的超链接。

这在任何情况下都是不恰当和不正确的。当这真的是一个人自己的编码风格问题时,没有对错之分。


为什么会这样?

它基于两个原因:

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

  2. 许多答案(包括@unwind最明显和公认的答案)要么完全或几乎完全基于意见(如果你自己铸造或重复自己会被添加到你的代码中的神秘“混乱”会很糟糕)并显示省略演员表的明确而集中的倾向。他们一方面争论演员阵容的冗余,但更糟糕的是,他们争论解决由编程本身的错误/失败引起的错误——如果一个人想要使用.#include <stdlib.h>malloc()


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

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

    此答案中列出了优缺点的一个很好的概述:

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

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


  1. 最多遇到的一个原因是省略演员表的原因是演员表可能隐藏了一个错误。

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

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

    演员会隐藏一个错误。

    虽然这是真的,但它只显示了故事的一半,因为演员的遗漏只会是一个更大的错误的前瞻性解决方案 - 不包括stdlib.h使用malloc().

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

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

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


  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)。对于所有存储持续时间的对象,实现应支持基本对齐。以下类型的对齐要求应为基本对齐:

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

— 所有原子的、合格的或不合格的枚举类型;

— 所有原子的、合格的或不合格的指针类型;

— 其元素类型具有基本对齐要求的所有数组类型;57)

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

— 所有结构或联合类型,其所有元素都具有具有基本对齐要求的类型,并且没有一个元素具有指定非基本对齐的对齐说明符。

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

资料来源:C18,§6.2.8/2

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

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

来源。C18,§6.2.8/3

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

请注意你如何教育自己。

我建议您首先仔细阅读到目前为止所做的所有答案(以及他们可能指向失败的评论),然后在您或如果您没有malloc()针对特定案例提出结果时建立自己的意见。

请注意:

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


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

于 2020-06-12T19:20:34.013 回答
18

不,您不会转换malloc().

通常,您不会投射到或从void *.

不这样做的一个典型原因是失败#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++ 中,情况有所不同。在处理派生类的对象时,转换指针类型有些常见(并且正确)。void *因此,在 C++ 中,到和从的转换不是隐式的,这是有道理的。C++ 有一整套不同风格的转换。

于 2017-08-16T12:25:30.430 回答
17

我加入演员表只是为了表明不赞成类型系统中的丑陋漏洞,它允许以下代码段之类的代码在没有诊断的情况下编译,即使没有使用演员表来导致错误的转换:

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

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

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

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

/* 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_qual仅用于删除constor volatile,但程序更改为涉及类型转换,您将获得诊断,并且您将不得不使用强制转换组合来获得所需的转换。

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

     -Wold-style-cast(仅限 C++ 和 Objective-C++)
         如果使用旧样式(C 样式)强制转换为非 void 类型,则发出警告
         在 C++ 程序中。新型演员表(dynamic_cast,
         static_cast、reinterpret_cast 和 const_cast)不太容易受到攻击
         到意想不到的效果,更容易搜索。

如果您的 C 代码编译为 C++,您可以使用此-Wold-style-cast选项找出所有(type)可能出现在代码中的强制转换语法,并通过从上述宏(或必要时组合)。

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

于 2016-03-30T00:23:45.463 回答
16

尽可能在 C 中编程时最好的做法是:

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

此过程允许您利用 C++ 严格类型检查,从而减少错误数量。特别是,此过程会强制您包含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...
于 2015-06-12T15:23:56.197 回答
16

我更喜欢做演员,但不是手动的。我最喜欢的是使用glib 中的g_newg_new0宏。如果不使用 glib,我会添加类似的宏。这些宏在不影响类型安全的情况下减少了代码重复。如果类型错误,您将在非空指针之间获得隐式转换,这将导致警告(C++ 中的错误)。如果您忘记包含定义g_newand的标头g_new0,您将收到错误消息。g_new并且g_new0两者都采用相同的参数,不像malloc那样采用的参数少于calloc. 只需添加0即可获得零初始化内存。代码可以用 C++ 编译器编译而无需更改。

于 2016-06-29T07:30:41.113 回答
14

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

于 2015-09-10T15:58:49.030 回答
12

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

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

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

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

于 2017-10-03T13:13:38.653 回答
10

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

于 2015-07-29T05:53:42.437 回答
9

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

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

于 2016-07-18T10:36:57.243 回答
9
  1. 如前所述,C 不需要它,但 C++ 需要它。

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

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

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

    因为stdlib.h包含了 malloc 的原型,所以找到了。在没有 malloc 原型的情况下,标准要求 C 编译器假定 malloc 返回一个 int。如果没有强制转换,则在将此整数分配给指针时发出警告;但是,使用演员表时,不会产生此警告,从而隐藏了一个错误。

于 2016-11-08T10:09:54.020 回答
1

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

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

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

  1. 如果为type分配内存,则使用强制转换。

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

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

ptr = malloc(sizeof *ptr);

广告 1

第一种方法通过为给定类型分配内存来确保正确的大小,然后对其进行强制转换以确保将其分配给正确的指针。如果使用了不正确的类型,ptr那么编译器将发出警告/错误。如果类型ptr改变了,那么编译器会指向代码需要重构的地方。

而且,第一种方法可以组合成一个类似于newC++中运算符的宏。

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

此外,如果ptris ,此方法有效void*

广告 2

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

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

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

于 2022-01-17T11:11:40.473 回答
0

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

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

于 2020-03-05T15:56:20.197 回答