【代码规范】详解nullptr、NULL、0
【代码规范】详解nullptr、NULL、0
最近一直搞不清楚 nullptr, NULL, '\0'这三者的真正区别,因为有的时候会发现,混用这三种用法,编译器也不会报错,在这里对相关的一些定义和使用方式进行整理,用于后续的使用说明。
欢迎大大们纠错~
null 和 NULL
C和C++语言对大小写是敏感的,也就是说null和NULL本质上是区别对待的。其实本质上null和NULL都是符号,只是在不同的编译器上NULL被宏定义指定内容,null没有定义而已。
例如在vs环境中,NULL被指定为0,代码如下。
我们可以这样写去验证以上的说法:
结果如下:
虽然可以这样使用,但是为了代码的可读性和规范着想,我们尽量不要编写这样的代码,了解原理即可。
NULL 和 nullptr
根据上面,我们知道了NULL本身是符号,只是不同编译器给出了不同的定义。刚刚看到了vs的定义,下面看下gcc对NULL的定义:
1) 如果gcc是c 语言模式而且gcc版本低于3.0,那么定义NULL 为 void* 类型
2) 如果gcc是c++ 语言模式,而且是32位,那么定义NULL 为无类型的0
3) 如果gcc是c++ 语言模式,而且是64位,那么定义NULL 为long long 类型的0
既然NULL可以被定义成不同的类型,那么为什么会出现nullptr呢,具体原因大家可以看下以下的代码,究竟是哪个函数会被调用。
发现在大多数的环境下结果如下,函数2无法调用。
为了解决这种二义性,nullptr应运而生,C++是强类型语言,又有模板、重载之类需要编译器“依类型随机应变”的东西,所以作为指针
型的0和整数类型的0就必须分开,不然会带来很多麻烦。
所以,和整数大家族相关,请用0(或自己重新定义的NULL,因为某些工程/实现可能把NULL定义成nullptr或者(void*) 0),和指针大家族相关,请用nullptr,这样才能写出尽量不出意外的程序。
NULL 和 0
其实NULL和0的关系在上面已经讲的差不多了,因为C++中不能将void *类型的指针隐式转换成其他指针类型,而又为了解决空指针的问题,所以C++中引入0来表示空指针,在一些编译器上又会用#define NULL ((void *)0)进行定义。
实际上C++的书都会推荐说C++中更习惯使用0来表示空指针,因为使用0来做为空指针会比使用NULL来做空指针会让你在编程时更加警觉,不过0代表空指针并不能避免上面说的二义性的问题,真正解决问题还得依靠nullptr。所以再次重复下,和整数大家族相关,请用0,和指针大家族相关,请用nullptr。
0的相关
‘\0’是一个“空字符”常量,它表示一个字符串的结束,它的ASCII码值为0,与’0‘的ASCII码值48是不一样的。
一般来说 0是整形常量,‘\0’是字符常量,存储方式不同,但是空字符的定义为“所有的位为 0 的字节称为 空字符(null character)”。也就是说,空字符是值为 0 的字符。,'\0'是一个常量,等同于0,(这个地方理解的不够深入)。
‘0’ 代表字符0, ASCII码为48。
“0”代表字符串0,尾部有不可见的’\0‘。
这个地方有一些需要注意的一些使用方法如下,代码如下图:
看起来执行结果没有什么问题,你可能会说说来说去,那还不都是 0 嘛。
确实在大部分的情况下是这样的,但背后的事情却异常复杂。标准允许将 NULL 定义成 (void*)0,所以在 NULL 被定义成 (void*)的时候,如果使用 NULL 来结束字符串,编译器必然会提示警告存在可能性空指针的区域并未清0,引发未知的错误。
所以在C++中NULL不可以用于字符串的末尾,支持0和'\0'作为字符串结尾。