C++中宏NULL的定义
根据Leon的回答,在函数有多个重载形式时,\0
会优先选择参数类型为 char
的重载形式。然而需要注意的是,在典型的编译器上,NULL
实际上会优先选择参数类型为 int
而不是 void*
的重载形式!
造成这种混淆的原因可能是 C 语言允许将 NULL
定义为 (void*)0
。但是,C++ 标准明确规定了:(draft N3936, page 444):
NULL
的可能定义包括0
和0L
,但不包括(void*)0
。
这种限制是必要的,因为例如 char *p = (void*)0
是合法的 C 代码,但是不合法的 C++ 代码;而 char *p = 0
则在两者中都是合法的。
在 C++11 及以上版本中,如果需要一个行为类似指针的空常量,应使用 nullptr
。
Leon的建议在实践中如何工作
这段代码定义了单个函数的多个重载形式。每个重载形式输出参数类型:
#include <iostream>
void f(int) {
std::cout << "int" << std::endl;
}
void f(long) {
std::cout << "long" << std::endl;
}
void f(char) {
std::cout << "char" << std::endl;
}
void f(void*) {
std::cout << "void*" << std::endl;
}
int main() {
f(0);
f(NULL);
f('\0');
f(nullptr);
}
在 Ideone 上运行此代码输出
int
int
char
void*
因此,我认为过载的问题不是实际应用中的问题,而是一种病态情况。在C++11中,
NULL
常量无论如何都会出现错误,应该替换为
nullptr
。
如果NULL不是零怎么办?
另一个病态案例由
Andrew Keeton在另一个问题中提出:
请注意,在C语言中什么是空指针。这并不取决于底层架构。如果底层架构将空指针值定义为地址0xDEADBEEF,则由编译器来解决这个问题。
因此,在这种有趣的架构上,以下方法仍然是检查空指针的有效方法:
if (!pointer)
if (pointer == NULL)
if (pointer == 0)
下面是无效的检查空指针的方法:#define MYNULL (void *) 0xDEADBEEF
if (pointer == MYNULL)
if (pointer == 0xDEADBEEF)
总的来说,我认为这些差异大多是风格上的。如果您有一个接受int
参数的函数和一个重载了该函数并接受char
参数的函数,并且它们的功能不同,当您使用\0
和NULL
常量调用它们时,您将会注意到它们之间的区别。但是,一旦将这些常量放入变量中,差异就消失了,因为所调用的函数是从变量的类型推导出来的。
使用正确的常量使代码更易于维护,并传达含义更清晰。当您需要表示数字时,请使用0
,当您需要表示字符时,请使用\0
,当您需要表示指针时,请使用nullptr
。Matthieu M.在评论中指出,GCC存在一个错误,其中将char*
与\0
进行比较,而本意是对指针进行解引用并将char
与\0
进行比较。如果代码库中使用了适当的风格,则此类错误更容易被检测到。
回答您的问题,实际上没有真正的用例会阻止您可以互换使用\0
和NULL
。只是出于风格和一些边缘情况的原因。
-Wzero-as-null-pointer-constant
翻译成中文为“将零视为空指针常量”。 - Biffennullptr
,而不是NULL
。 - Basile Starynkevitchchar*
与\0
进行了比较,这很可能是作者在进行比较之前忘记对指针进行解引用(以获取字符)的结果。正确的类型设置可以使工具更加强大。 - Matthieu M.