C++ 笔记(28)— C++ 中 NULL和 nullptr 的区别

最近看公司代码的时候发现在判断指针是否为空的时候,有的时候用的是 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 的定义为 00L (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_tprvalue

2. C 中的 NULL

C 语言中,NULL 通常被定义为: #define NULL ((void *)0)

所以说 NULL 实际上是一个空指针,如果在 C 语言中写入以下代码,编译是没有问题的,因为在 C语言中把空指针赋给 intchar 指针的时候,发生了隐式类型转换,把 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. 总结

NULLC++ 中就是 0,这是因为在 C++void* 类型是不允许隐式转换成其他类型的,所以之前 C++ 中用 0 来代表空指针,但是在重载整形的情况下,会出现上述的问题。

所以,C++11 加入了 nullptr ,可以保证在任何情况下都代表空指针,而不会出现上述的情况。

因此,建议使用 nullptr 替代 NULL ,而 NULL 就当做 0 使用。

参考:
https://blog.csdn.net/qq_18108083/article/details/84346655

上一篇:Leetcode 897. 递增顺序搜索树


下一篇:代码题(64)— 旋转链表、反转链表、分隔链表