最近看公司代码的时候发现在判断指针是否为空的时候,有的时候用的是 NULL
, 有的时候用的是 nullptr
感觉很奇怪,好奇心驱使我查了下两者的区别,发现还是有很多细节需要学习的。
1. NULL 在 C/C++ 中的定义
先来看下 C99
是怎么定义 NULL
的:
NULL can be defined as any null pointer constant. Thus existing code can retain definitions of NULL as 0 or 0L, but an implementation may also choose to define it as (void*)0. This latter form of definition is convenient on architectures where sizeof(void*) does not equal the size of any integer type. It has never been wise to use NULL in place of an arbitrary pointer as a function argument, however, since pointers to different types need not be the same size. The library avoids this problem by providing special macros for the arguments to signal, the one library function that might see a null function pointer.
大意就是: NULL
可以定义为任何空指针常量。因此,现有的代码可以保留 NULL
的定义为 0
或 0L
(32位和64位的区别),或者直接就是由 0
或者 0L
转成的成 void*
。
接下来我们来看下 C++ 14
(N4296)中所定义的 null pointer
。
A null pointer constant is an integer literal (2.13.2) with value zero or a prvalue of type std::nullptr_t.
A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type. Such a conversion is called a null pointer conversion. Two null pointer values of the same type shall compare equal. The conversion of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the sequence of a pointer conversion followed by a qualification conversion (4.4). A null pointer constant of integral type can be converted to a prvalue of type std::nullptr_t. [ Note: The resulting prvalue is not a null pointer value. —end note ]
第一句话大意是 空指针常量是一个值为 0
的整型字面值或一个类型为 std::nullptr_t
的 prvalue
。
2. C 中的 NULL
在 C
语言中,NULL
通常被定义为: #define NULL ((void *)0)
所以说 NULL
实际上是一个空指针,如果在 C
语言中写入以下代码,编译是没有问题的,因为在 C
语言中把空指针赋给 int
和 char
指针的时候,发生了隐式类型转换,把 void
指针转换成了相应类型的指针。
int *pi = NULL;
char *pc = NULL;
3. C++ 中的 NULL
以上代码如果使用 C++
编译器来编译则是会出错的,因为 C++
是强类型语言,void*
是不能隐式转换成其他类型的指针的,所以实际上编译器提供的头文件做了相应的处理:
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
在 C++
中,NULL
实际上是 0
。
因为 C++
中不能把 void*
类型的指针隐式转换成其他类型的指针,所以为了空指针的表示问题,C++
引入了 0
来表示空指针,这样就有了上述代码中的 NULL
宏定义。
但是实际上,用 NULL
代替 0
表示空指针在函数重载时会出现问题,程序执行的结果会与我们的想法不同,举例如下:
#include <iostream>
using namespace std;
void func(void* t)
{
cout << "func1" << endl;
}
void func(int i)
{
cout << "func2" << endl;
}
int main()
{
func(NULL);
return 0;
}
运行后输出结果:
main.cpp: In function ‘int main()’:
main.cpp:16:14: error: call of overloaded ‘func(NULL)’ is ambiguous
func(NULL);
报错信息显示有歧义。
3. C++ 中的 nullptr
为解决 NULL
代指空指针存在的二义性问题,也就是上面遇到的报错问题,在C++11
版本中特意引入了 nullptr
这一新的关键字来代指空指针,如下所示
#include <iostream>
using namespace std;
void func(void* t)
{
cout << "func1" << endl;
}
void func(int i)
{
cout << "func2" << endl;
}
int main()
{
func(nullptr); // func1
return 0;
}
可以看到程序可以正常输出与我们预期相同的结果。
4. 总结
NULL
在 C++
中就是 0
,这是因为在 C++
中 void*
类型是不允许隐式转换成其他类型的,所以之前 C++
中用 0
来代表空指针,但是在重载整形的情况下,会出现上述的问题。
所以,C++11
加入了 nullptr
,可以保证在任何情况下都代表空指针,而不会出现上述的情况。
因此,建议使用 nullptr
替代 NULL
,而 NULL
就当做 0
使用。
参考:
https://blog.csdn.net/qq_18108083/article/details/84346655