空指针:C和C++之间的区别

22

我正在尝试理解C和C++在void指针方面的差异。以下代码在C中可以编译通过,但在C++中无法编译通过(使用gcc / g ++-ansi-pedantic-Wall进行所有编译):

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

因为malloc返回void*,而C++不允许将其分配给int*,而C则允许。

然而,在这里:

void foo(void* vptr)
{
}

int main()
{
    int* p = (int*) malloc(sizeof(int));
    foo(p);
    return 0;
}

为什么C++和C编译时都没有任何投诉?

K&R2说:

任何指向对象的指针都可以转换为类型为void *的指针,不会丢失信息。如果将结果转换回原始指针类型,则可以恢复原始指针。

这就几乎涵盖了C中所有关于void*转换的内容。那么C++标准规定了什么?


GMan准确地解释了为什么会出现错误。话说,如果你正在编写C++代码,那么应该使用new/new[]和delete/delete[]来替代malloc/calloc和free/free。 - Michael Aaron Safyan
3个回答

41

在C语言中,指针与void*之间的转换总是隐式的。

在C++中,从T*void*的转换是隐式的,但是void*到其他类型的转换需要进行强制类型转换。


1
你能给你第二个陈述提供一个来源吗?它是否写在C++标准中? - zaharpopov
6
实际上,没有太多可引用的内容。它在第4.10.2节中简单地表明T*可以转换为void*。它省略了反向转换,这意味着你必须使用强制转换。 - GManNickG
@zaharpopov:查找reinterpret_cast<>或static_cast<>。 - Martin York
1
@GMan:通过明确不声明void的转换,意味着不可能这样做(即从void转换为任何其他指针类型是不允许的(隐式地))。然后,通过查看强制转换运算符的定义,您可以了解这些运算符允许对对象执行的操作。它们在将void*转换为其他类型的定义上非常清楚。 - Martin York
2
@GMan:如果你说的“在C中,指针转换总是隐式的”是指对void *类型的转换,那么你是对的。否则,在指针转换方面,C和C++几乎一样严格。例如,在C中,没有从char *int *的隐式转换。历史上,C编译器通常将指针转换错误报告为“警告”,这导致了一个关于C允许所有隐式指针转换的错误观念。然而,这只是一个谬论。 - AnT stands with Russia
是的,我指的是你说的话,我没有意识到那有多么不清楚。关于约克的评论,我明天会尝试添加一些信息,但现在我必须睡觉了。 - GManNickG

7

C++比C语言更强类型。许多转换,尤其是那些涉及不同值解释的转换,需要显式转换。在C++中,new运算符是一种类型安全的方式,在堆上分配内存,不需要显式转换。


-1

了解指针类型转换不需要执行额外的CPU指令是很有用的。它们在编译时分析以理解开发人员的意图。void *是一个不透明指针。它只表示所指对象的类型未知。C是弱类型的。它允许直接隐式转换 (void *) 和任何 (T*) 之间的转换。C++是强类型的。从 (void *) 到 (T*) 的转换对于强类型语言来说并不是一个好的情况。但是C++必须保持与C的向后兼容性,因此必须允许这种转换。那么指导原则就是:显式优于隐式。因此,如果您希望将 (void*) 转换为某个特定的 (T*) 指针,您需要在代码中明确写出来。从 (T*) 到 (void*) 的转换不需要显式转换,因为在 (void*) 指针上没有太多可以直接操作的内容(虽然可以调用 free())。因此,(T*) 到 (void*) 的转换是相当安全的。


2
指针转换是否需要CPU指令取决于具体实现。C和C++语言中绝对没有要求这些转换纯粹是概念性的(即不需要CPU指令)。相反,这两种语言都特别设计为允许不同指针类型的不同表示方式。虽然“理解”在典型情况下转换确实在CPU级别上什么也不做可能确实有用,但编写依赖于该假设的C或C++代码是一个严重的错误。 - AnT stands with Russia
2
我不明白“保持向后兼容”的意义。在C++中,需要使用显式转换才能从void *进行转换。这已经与C向后兼容了。 - AnT stands with Russia
C++与C不是完全向后兼容的。它只是在必要时提供了使迁移尽可能简单的方法。从弱类型到强类型的转换自然会导致兼容性问题。C++仅尝试提供简单的方式(例如对void指针进行显式类型转换)来简化迁移过程。 - Shailesh Kumar
2
@AndreyT:为了加强你的观点,从派生类和基类之间进行转换(特别是在多重继承中)可能需要CPU来将指针移动到内存中对象的适当部分。 - Richard Corden
1
C++ 与 C 相同,都受到隐式类型提升规则的影响,这使得 C++ 也成为一种弱类型语言。"强类型" 不仅仅是指空指针。 - Lundin
C和C++都不是强类型编程语言。请参考这个答案了解详细解释。 - IInspectable

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