用类型转换来处理malloc返回的指针是一种更好的做法吗?

4
以下是C代码,比较int指针a和b的定义:
```c int *a; int* b; ```
请注意,这两个指针的定义方式是等效的。
#include <stdio.h>
#include <stdlib.h>

int main()
{
  int *a=malloc(sizeof(int));
  int *b=(int *)malloc(sizeof(int));
  return(0);
}

在使用malloc函数时,将返回的void指针进行类型转换是否有优势?或者当将其赋值给左侧的int指针时,它是否会自动进行类型转换?在什么情况下,如果有必要而不是强制性,它可能会证明是必要的?

请澄清这里是否适用隐式类型转换,即右侧的类型转换为左侧的类型。

7个回答

16

在C语言中不需要进行类型转换,但是为了与C++兼容,你可能需要进行类型转换。这是C不是C++子集的情况之一。

以下代码在C中可以编译但在C++中不能:

int *a=malloc(sizeof(int));
下面的代码可以在 C 和 C++ 中编译通过:
int *b=(int *)malloc(sizeof(int));

2
C++更加严格地处理指针类型转换的其中一个原因是因为在向上或向下转换类层次结构时,指针可能会发生变化。 - Anton
3
严格要求更好,因为这样可以避免更多的错误。 - Brian R. Bondy
2
@Brian。但是哪种方式更“严格”呢?如果你添加了转换,然后粘贴到C++中,现在一个可疑的malloc()行将会默默地编译通过,这可能是不好的。我相信你希望C++编译器标记出需要人工关注的malloc()行。相对于C/C++而言,“严格”并没有明确定义的含义,但我可以理解无转换更严格的论点。 - DigitalRoss
4
对我来说,在.c文件中使用malloc有点像带着外国口音说话。 - asveikau

12

不需要、需要、从不

  • 有些人会强制类型转换,但我不会。
  • 是的,类型转换会“自动”发生。
  • C语言中从不需要这样做。
  • 以某种奇怪的方式,强制类型转换结果会“损害”C++的可移植性。在C++中引用的模块很可能会被编译为C语言,在这种情况下并不重要。但如果代码被复制粘贴到C++中,我认为你希望每一行都被标记为可疑的代码行,因为在C++中调用malloc()函数的代码行是一个可疑的代码行。
  • 部分原因是由于早期的K&R C没有void类型,所以malloc()函数返回一个char *类型。现在,你需要进行类型转换。因此,强制类型转换malloc()的设计模式得以发展,并影响了所有编写下一组代码的人们,今天仍有人阅读这些代码,并将该模式继续传承下去。但是,C89已经具有了void类型,因此是时候简化代码了。
  • 根据实际操作方式,强制类型转换可能会违反DRY(也称为DIE)原则。正如Chris Lutz所指出的那样,这会不必要地降低抽象层次。由于在C程序中抽象层次本来就不是很高,因此我宁愿不失去我们现有的层次。

你的意思是说添加强制转换会降低兼容性吗?因为eliben和brian的回答说C++需要通过强制转换知道指针类型。 - user191776
3
他们是正确的。我的观点仅仅是,在不太可能的复制粘贴到C++情况下,你真的应该给每个malloc()行人工关注,这样就更好了,不要让这些行像一切都很顺利一样静默编译。 - DigitalRoss
3
对我来说致命的是强制类型转换会使得在最小的代价下无法更改变量c的类型: 在float *arr = (float *)malloc(10);中,如果我们需要更高的精度,就必须将两个float更改为double,如果后来我们使用了realloc()重新分配内存,但忘记在那里更改类型转换,会怎么样呢? - Chris Lutz

9
简单来说:
如果你已经包含了 stdlib.h,就像你应该做的那样,那么强制转换将不起任何作用,并且应该将其删除。毕竟,你已经指定了类型。
如果没有包含,那么强制转换将掩盖错误,这是不好的。
在 C 代码中永远不要使用强制转换。
在 C++ 中,强制转换是必需的,因为 C++ 不允许 void * 和其他指针类型之间的隐式转换。另一方面,在 C++ 中有比 malloc() 更好的东西,比如 new 或容器类。
编写可以在两种语言中编译的代码是无意义的。你应该始终知道你正在编写哪种语言,并使用一个在任何一种语言中都较差的构造强制你使用子集。我熟悉的 C++ 编译器也会编译 C 代码,而且 C++ 中有明确的条款可以轻松地与 C 代码链接。如果你将其编译为 C++,(没有强制转换的)错误消息将指出你的错误。
所有强制转换将做的只是掩盖可能在其他地方咬你的错误。它不会做任何有用的事情。不要这样做。

8
在C语言中,强制类型转换是不必要的。函数malloc返回一个void*指针,C标准规定:

指向void的指针可以转换为任何未完成或对象类型的指针,反之亦然;结果应与原始指针相等。

此外,K&R2还说:

任何指向对象的指针都可以转换为void*类型而不会丢失信息。如果将结果转换回原始指针类型,则可以恢复原始指针。与Par.A.6.6中讨论的指针到指针转换不同,后者通常需要显式强制类型转换,指针可以被分配给和从void*类型的指针中获取,并且可以与它们进行比较。

关于C++兼容性可能需要注意,因为在C++中需要进行强制类型转换。但是,在我的看法中,这几乎不相关,因为惯用的C++调用方式是使用new而不是malloc


这是非常相关的,例如如果您计划编写C++程序来使用您的C代码。 - Brian R. Bondy
5
如果您的C++程序需要使用您的C代码,它可以直接使用它,而无需将其移植到C++。因此eliben的评论认为源代码与C++的兼容性不是问题是正确的。 - Tomek Szpakowicz
例如,您可以在头文件中编写代码,然后将其包含到C++程序中。 - Brian R. Bondy
@Brian - 但是如果你的代码存在于一个 .c 文件中,而你的 C++ 代码存在于一个 .cc/.cxx/.cpp 文件中,从 C++ 调用 C 代码就没有问题。真正需要担心的地方是头文件。或者那些可能会将你的代码复制粘贴到 C++ 文件中的人。 - asveikau
我同意你们的观点,我的意思只是存在问题是可能的,而不是首选方式。 - Brian R. Bondy
显示剩余5条评论

4
调用malloc()函数并强制类型转换返回值是C++中的习惯用法,在C语言中不必要。只有在想将代码编译为C++时才需要这样做,但由于C和C++是具有不同语义的不同语言,因此不应这样做。
仅当您想创建一个C库并在头文件中定义内联函数以供C++使用时,才有意义。随着链接时优化的出现,希望此操作不再必要,因为即使在不同的源文件中定义了函数,它们也可以被内联。
至于声称显式强制类型转换增加可读性的人,请考虑以下示例。
int *b=(int *)malloc(sizeof(int));

为什么将类型重复三次比只写一次更易读?

int *b = malloc(sizeof *b);

我不太理解。
C++0x甚至添加了类型推断以消除类似的重复,所以我认为这并不具有争议性。

3
如果我们谈论的是C语言,最佳实践是不要强制转换malloc()的结果。如果我们谈论的是C++,最佳实践是使用new而不是malloc()1
我建议不要强制转换的原因是为了避免如果您忘记在作用域中包含stdlib.h或者其他情况下没有malloc()的原型时出现问题。直到C99之前,如果您有一个没有先前声明的函数调用,编译器会隐式地将函数调用类型设置为返回int。没有强制转换,这将导致不兼容的赋值警告。有了强制转换,警告被抑制,可能会出现运行时错误,因为从malloc()返回的值将从指针转换为整数再转换回指针,这不能保证是有意义的。
如果您正在从C移植到C ++,最好一开始就将malloc()转换为new


1
“在使用malloc函数返回的void类型指针时,进行强制类型转换是否有任何好处呢?”

是的。这样更加清晰明了。这也是我写代码时会这么做的原因。

a = b + (c * d);

现在,我知道这里不需要使用“()”,因为算术运算符的优先级规则,但它们可以帮助我(和其他人)清晰地看到我的意图。

$.02等等。:)

-k


你说的 $.02 是什么意思? - user191776
2
0.02美元=0.924983813印度卢比 - Google - Josh Lee
“Two cents' worth”是美国的一个习语,意思是“这只是我的个人观点”。有人可能会说自己在讨论中加入了自己的“two cents”。 - David Thornley

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