TheRiver | blog

You have reached the world's edge, none but devils play past here

0%

null和nullptr

参考

【C++11新特性】 nullptr关键字

invalid conversion from void* to char*

warning: passing NULL to non-pointer argument of ‘std::thread::thread

nullptr

前言

最近面试遇到的一个问题,平时没怎么注意到,今天研究了下,顺便记录下来.

NULL

1
2
3
4
5
6
7
#ifndef NULL
# if defined __STDC__ && __STDC__
# define NULL ((void *) 0)
# else
# define NULL 0
# endif
#endif

nullptr

nullptr是C++11语言标准用来表示空指针的常量值[1],可以指派给任意类型的指针变量[2]。部分编译器将之视为一个关键字,例如Visual Studio[3],部分使用旧标准的C++编译器则未实现需要自行定义[4]或引入额外的头文件[2]。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#ifndef _LIBCPP_NULLPTR
#define _LIBCPP_NULLPTR
#include <__config>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif
#ifdef _LIBCPP_HAS_NO_NULLPTR
_LIBCPP_BEGIN_NAMESPACE_STD
struct _LIBCPP_TEMPLATE_VIS nullptr_t
{
void* __lx;
struct __nat {int __for_bool_;};
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR nullptr_t() : __lx(0) {}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR nullptr_t(int __nat::*) : __lx(0) {}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR operator int __nat::*() const {return 0;}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
operator _Tp* () const {return 0;}
template <class _Tp, class _Up>
_LIBCPP_INLINE_VISIBILITY
operator _Tp _Up::* () const {return 0;}
friend _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR bool operator==(nullptr_t, nullptr_t) {return true;}
friend _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR bool operator!=(nullptr_t, nullptr_t) {return false;}
};
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR nullptr_t __get_nullptr_t() {return nullptr_t(0);}
#define nullptr _VSTD::__get_nullptr_t()
_LIBCPP_END_NAMESPACE_STD
#else // _LIBCPP_HAS_NO_NULLPTR
namespace std
{
typedef decltype(nullptr) nullptr_t;
}
#endif // _LIBCPP_HAS_NO_NULLPTR
#endif // _LIBCPP_NULLPTR

在c语言中,NULL是void*,在C++中NULL是0.C++ 11中使用nullptr来表示空指针.

代码

C语言

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
#include <stdlib.h>

void fun1(void* a)
{
printf("void\n");
}

void fun2(int a)
{
printf("int\n");
}

void fun3(char* a)
{
printf("char*\n");
}

int main()
{
//fun1(NULL); //void*
//fun2(NULL); //expected 'int' but argument is of type 'void *'|
fun3(NULL); //char*

return 0;
}

C++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>

using namespace std;

void fun(void*)
{
cout << "void" <<endl;
}

void fun(int )
{
cout << "int" <<endl;
}

void fun2(char *)
{
cout << "char*" << endl;
}

int main()
{
//fun(nullptr); //void*
fun(NULL); //int
//fun2(0); //char*
//fun2((void*)0); //无法将参数 1 从“void *”转换为“char *”

return 0;
}

原理

nullptr是关键字,并且是个prvalue,类型是nullptr_t。nullptr_t的原理是通过operator类型转换函数配合模板来进行任意指针类型的转换:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include "pch.h"
#include <iostream>
#include <vector>
#include <string>
using namespace std;


void func1(int*)
{
cout << "int*" << endl;
}

void func2(char*)
{
cout << "char*" << endl;
}

void func3(void*)
{
cout << "void*" << endl;
}

void func4(string*)
{
cout << "string*" << endl;
}

void func5(vector<int>*)
{
cout << "vector<int>*\n";
}

class a
{
public:
template <typename _Tp>
operator _Tp*()
{
return 0;
}
};

int main()
{
func1(nullptr);
func2(nullptr);
func3(nullptr);
func4(nullptr);
func5(nullptr);

a aa;
func1(aa);
func2(aa);
func3(aa);
func4(aa);
func5(aa);

return 0;
}
int*
char*
void*
string*
vector<int>*
int*
char*
void*
string*
vector<int>*

ending

74432233_p0_master1200.jpg

----------- ending -----------