NULL通常在指针的上下文中使用,并且通过多个标准库(例如<iostream>)中的宏来定义为整数0.'\0'是空字符,是8位零.顺便提一下,8位零等于整数0.
在某些情况下,虽然它被认为是可怕的风格,但这两者可以互换:
int *p='\0';
if (p==NULL) //evaluates to true
cout << "equal\n";
Run Code Online (Sandbox Code Playgroud)
要么
char a=NULL;
char b='\0';
if (a==b) //evaluates to true
cout << "equal again\n";
Run Code Online (Sandbox Code Playgroud)
关于SO已经有很多类似的问题; 例如,这个问题的最佳答案(NULL,'\ 0'和0之间的区别是什么)说"它们实际上不是一回事".
任何人都可以提供一个例子NULL和\0不能互换(优选实际应用,而不是一个病理情况)?
Leo*_*eon 52
任何人都可以提供一个例子,NULL和\ 0不能互换吗?
NULL和之间的差异'\0'可能会影响重载分辨率.
示例(在Coliru上查看):
#include <iostream>
// The overloaded function under question can be a constructor or
// an overloaded operator, which would make this example less silly
void foo(char) { std::cout << "foo(char)" << std::endl; }
void foo(int) { std::cout << "foo(int)" << std::endl; }
void foo(long) { std::cout << "foo(long)" << std::endl; }
void foo(void*) { std::cout << "foo(void*)" << std::endl; }
int main()
{
foo('\0'); // this will definitely call foo(char)
foo(NULL); // this, most probably, will not call foo(char)
}
Run Code Online (Sandbox Code Playgroud)
请注意,Coliru使用的gcc编译器定义NULL为0L,对于此示例,这意味着foo(NULL)解析为foo(long)而不是foo(void*).这个答案详细讨论了这个方面.
vll*_*vll 36
Leon是正确的,当同一个函数有多个重载时,\0更喜欢带参数类型的那个char.但是,重要的是要注意在典型的编译器上,NULL更喜欢带有类型参数的重载int,而不是类型void*!
可能导致这种混淆的是C语言允许定义NULL为(void*)0.C++标准明确声明(草案N3936,第444页):
[宏可能的定义
NULL]包括0和0L,但不会(void*)0.
这种限制是必要的,因为例如char *p = (void*)0有效的C但无效的C++,而char *p = 0两者都有效.
在C++ 11及更高版本中,nullptr如果需要一个行为指针的null常量,则应该使用它.
此代码定义了单个函数的多个重载.每个重载都输出参数的类型:
#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);
}
Run Code Online (Sandbox Code Playgroud)
在Ideone上输出
int
int
char
void*
Run Code Online (Sandbox Code Playgroud)
因此,我认为重载问题不是实际应用,而是病态案例.该NULL常数的行为错了,无论如何,并且应该被替换nullptr在C++ 11.
另一个问题是Andrew Keeton提出的另一个病理案例:
请注意,C语言中的空指针是什么.它与底层架构无关.如果底层架构的空指针值定义为地址0xDEADBEEF,那么由编译器来排除这个混乱局面.
因此,即使在这个有趣的架构上,以下方法仍然是检查空指针的有效方法:
Run Code Online (Sandbox Code Playgroud)if (!pointer) if (pointer == NULL) if (pointer == 0)以下是检查空指针的INVALID方法:
Run Code Online (Sandbox Code Playgroud)#define MYNULL (void *) 0xDEADBEEF if (pointer == MYNULL) if (pointer == 0xDEADBEEF)因为这些被编译器视为正常比较.
总而言之,我会说差异主要是风格.如果你有一个接受int和重载的函数char,并且它们的功能不同,当你用它们\0和NULL常量调用时,你会注意到它们之间的区别.但是只要将这些常量放在变量中,差异就会消失,因为调用的函数是从变量的类型中扣除的.
使用正确的常量可以使代码更易于维护,并更好地传达意义.0当你的意思是一个数字时,你应该使用,\0当你的意思是一个字符,nullptr当你指的是一个指针时.马修M.指出了意见,那GCC有一个bug,在其中char*进行比较\0,而目的是取消引用指针和比较char来\0.如果在代码库中使用了合适的样式,则更容易检测到这些错误.
要回答您的问题,实际上并没有一个实际的用例会阻止您使用\0和NULL互换.只是风格的原因和一些边缘情况.
请不要这样做.这是一种反模式,实际上是错误的.NULL用于NULL指针,'\0'是空字符.它们在逻辑上是不同的东西.
我不认为我见过这个:
int* pVal='\0';
Run Code Online (Sandbox Code Playgroud)
但这很常见:
char a=NULL;
Run Code Online (Sandbox Code Playgroud)
但这不是好形式.它使代码不那么便携,而且在我看来不太可读.它也可能在混合C/C++环境中引起问题.
它依赖于有关任何特定实现如何定义NULL的假设.例如,一些实现使用简单的
#define NULL 0
Run Code Online (Sandbox Code Playgroud)
其他人可能使用:
#define NULL ((void*) 0)
Run Code Online (Sandbox Code Playgroud)
我已经看到其他人定义为整数,以及各种奇怪的处理.
NULL在我看来,应仅用于表示无效地址.如果你想要一个空字符,请使用'\0'.或者将其定义为NULLCHR.但那不是那么干净.
这将使您的代码更具可移植性 - 如果您更改编译器/环境/编译器设置,则不会开始收到有关类型等的警告.这在C或混合C/C++环境中可能更为重要.
可能出现警告的示例:请考虑以下代码:
#define NULL 0
char str[8];
str[0]=NULL;
Run Code Online (Sandbox Code Playgroud)
这相当于:
#define NULL 0
char str[8];
str[0]=0;
Run Code Online (Sandbox Code Playgroud)
我们正在为char分配一个整数值.这可能会导致编译器警告,如果有足够的事件发生,很快您就看不到任何重要的警告.对我来说,这是真正的问题.代码中有警告有两个副作用:
在这两种情况下,实际的错误都可以通过,如果我们打扰阅读警告(或打开-Werror),编译器会捕获这些错误
是的,在解决重载功能时,它们可能表现出不同的行为.
func('\0')调用func(char),
而
func(NULL)调用func(integer_type).
您可以使用nullptr消除混淆,nullptr始终是指针类型,在分配/比较值或函数重载分辨率时不显示歧义.
char a = nullptr; //error : cannot convert 'std::nullptr_t' to 'char' in initialization
int x = nullptr; //error : nullptr is a pointer not an integer
Run Code Online (Sandbox Code Playgroud)
请注意,它仍然与NULL兼容:
int *p=nullptr;
if (p==NULL) //evaluates to true
Run Code Online (Sandbox Code Playgroud)
摘自C++ Programming Stroustrup第4版书:
在较旧的代码中,通常使用0或NULL而不是nullptr(第7.2.2节).但是,使用nullptr消除了整数(例如0或NULL)和指针(例如nullptr)之间的潜在混淆.
计算机程序有两种类型的读者.
第一种类型是计算机程序,如编译器.
第二种类型是人类,就像你自己和你的同事一样.
程序通常很好,只有一种类型的零代替另一种类型.正如其他答案所指出的那样,也有例外,但这并不重要.
重要的是你正在弄乱人类的读者.
人类读者非常敏感.通过使用错误的零,你是骗人的读者.他们会诅咒你.
被骗的人可以更容易地忽视错误.
被骗的人可以看到不存在的"虫子".当"修复"这些phanthom错误时,它们会引入真正的错误.
不要欺骗你的人类.你所撒谎的人之一就是你未来的自我.你也会诅咒你.