1、NULL和0
-
在C语言标准定义中,
NULL
的定义为(void *)0
这样的代码意味着可以进行强制类型转换一个
void *
类型的指针到任意类型的指针#define NULL (void*)0 char *p = NULL;
-
C++11之后
NULL
被定义为0,此时可以认为NULL不完全是一个空指针。#ifndef __cplusplus #define NULL ((void *)0) #else /* C++ */ #define NULL 0 #endif /* C++ */
-
C++是一门类型安全的语言,*无法将一个void 类型的指针隐式转换为其他类型
char *p = 0; char *p1 = NULL; char *p2 = (void *)0; // 报错 char *p3 = reinterpret_cast<char*>(NULL); // 强转可以
-
而这样又会引入另外一个重载的二义性问题
因为NULL的值实际是0,但是
char
也可以接收一个NULL(0)
值,但是NULL又被定义为0值,这样就会导致一个二义性问题。void func(int ) {std::cout << "func(int)" << std::endl; } void func(char *) {std::cout << "func(char *) " << std::endl; }void test1() {func(0); // 调用func(int) // func(NULL); // 报错func(reinterpret_cast<char *>(NULL)); //强转可以调用func(char *) }
-
2、nullptr
-
为了解决上面带来的二义性问题,C++11之后引入了
nullptr
来专门区分0和空指针。 -
nullptr
的类型为std::nullptr_t
,nullptr
是一个std::nullptr_t
的纯右值 -
nullptr
能够隐式的转换为任何指针,因此空指针的时候推荐使用nullptr
-
而通过
nullptr
就可以解决上面的二义性问题void test2() {func(0); // 调用func(int)func(nullptr); // 调用func(char *) }
3、nullptr_t的定义
- 可以看到
nullptr
被定义为nullptr_t
类型 - 同时
nullptr_t
的类型长度与void *
长度相同
namespace std
{typedef __SIZE_TYPE__ size_t;typedef __PTRDIFF_TYPE__ ptrdiff_t;#if __cplusplus >= 201103Ltypedef decltype(nullptr) nullptr_t;
#endif
}
static_assert(sizeof(std::nullptr_t) == sizeof(void *));
- 而
nullptr_t
也可以定义一个其他指针的空指针对象并且与nullptr
有相同的能力,而且被创建的对象是一个左值
void test3()
{std::nullptr_t null1;std::nullptr_t null2;std::cout << "&null1 = " << &null1 << std::endl;std::cout << "&null2 = " << &null2 << std::endl;
// std::cout << "&nullptr = " << &nullptr << std::endl; //报错,右值没有地址
}