C/C++ null 类型

C/C++学习笔记

概述

在 C/C++ 中,NULL、0、’\0’的本质都是一样的,都是值 0。但是其中的含义不一样。

NULL

NULL 是指针类型,含义为空指针,值为 0。

1
# define NULL (void*)0

在被编译器编译时,若将 int 类型赋值为 NULL 会出现相应的 warning 提示。

‘\0’

‘\0’表示的是 ascii 的 0 号字符,表示为空即 0x00,转换成数字即为 0。

0

表示的是数字 0,即0x00。

nullptr

在 C++ 中,不推荐使用 NULL 来作为空指针的初始值,而是使用 nullptr。

在 C++ 中 NULL 在 gcc 的 stddef.h 中被这样定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* A null pointer constant.  */

#if defined (_STDDEF_H) || defined (__need_NULL)
#undef NULL /* in case <stdio.h> has defined it. */
#ifdef __GNUG__
#define NULL __null
#else /* G++ */
#ifndef __cplusplus
#define NULL ((void *)0)
#else /* C++ */
#define NULL 0
#endif /* C++ */
#endif /* G++ */
#endif /* NULL not defined and <stddef.h> or need NULL. */
#undef __need_NULL

可以看到,在 C++ 中 NULL 的含义仅为数字 0。

在 C++ 中不能将 void* 类型的指针隐式转换成其他的指针类型,是因为 C++ 认为类型转换不安全,所以禁止了 void* 转换成其他指针的功能,这个结果导致 C 中对 NULL 的定义无法编译通过。

而且,NULL 因为被定义成为了 0,因此在函数重载的时候会出现问题,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
void foo(void* p) {
std::cout << "p is pointer" << std::endl;
}
void foo(int p) {
std::cout << "p is numbre" << std::endl;
}

int main() {
foo(NULL);

return 0;
}

会产生报错 “call of overloaded ‘foo(NULL)’ is ambiguous.”,因为两个函数都可以被匹配上。

这就引出了 nullptr。nullptr 在 c++ config.h 中被定义:

1
2
3
4
5
6
7
8
9
10
11
 // For full details see:     
// http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/namespaces.html
namespace std
{
typedef __SIZE_TYPE__ size_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t;

#if __cplusplus >= 201103L
typedef decltype(nullptr) nullptr_t;
#endif
}

nullptr 并非整型类别,甚至也不是指针类型,但是能转换成任意指针类型。nullptr 的实际类型是 std:nullptr_t。

将空指针赋值为 nullptr 就可以避免上述的问题,配合模板更可以做到完美转发。