区分0的4种面孔

0在C/C++语言中绝对是个多面手,它扮演着多样的角色,拥有着多种面孔。总结起来包括以下几种角色:整型0、空指针NULL、字符串结束标志‘\0’、逻辑FALSE/false,不同的角色适用于不同的情形,下面我们按照上述顺序一一介绍。

这是我们最熟悉的一个角色。作为一个int 类型,整型0 占据32 位的空间,其二进制表示为:

00000000 00000000 00000000 00000000

它的使用方式最为简单直接,未经修饰,如下所示:
int nNum = 0; // 赋值
if( nNum == 0 ) // 比较

空指针NULL
NULL 是一个表示空指针常量的宏,在C/C++ 标准中有如下阐述:
在文件<clocale>、<cstddef>、<cstdio>、<cstdlib>、<cstring>、<ctime> 或者<cwchar> 中定义的NULL 宏,在国际标准中被认为是C++ 空指针常量。指针与int 类型所占空间是一样的,都是32 位。那么,空指针NULL 与0 又有什么区别呢?还是让我们看一下windef.h 中NULL 的定义吧:
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif

通过定义我们可以看出,它们之间其实是没有太大的区别,只不过在C 语言中定义
NULL 时会进行一次强制转型。

需要注意的是,这里的0 与整型的0 还是存在区别的。例如,int* pValue = 0; 是合法的,而int* pValue = 1; 则是不合法的。这是因为0 可以用来表示地址,但常数1 绝对不行。

作为指针类型时,推荐按照下面的方式使用0:
float* pNum = NULL; // 赋值
if( pNum == NULL ) // 比较

字符串结束标志'\0'
'\0' 与上述两种情形有所不同,它是一个字符。作为字符,它仅仅占8 位,其二进制表示为:
00000000

因为字符类型中并没有与0000 0000 对应的字符,所以就创造出了这么一个特殊字符。(对于类似'\0' 这样的特殊字符,我们称之为转义字符。)在C/C++ 中,'\0' 被作为字符串结束标志来使用,具有唯一性,与'0' 是有区别的。

作为字符串结束符,0 的使用有些特殊。不必显式地为字符串赋值,但是必须明确字符串的大小。例如,在下面的代码中,“Hello C/C++”只有11 个字符,却要分配12 个字符的空间。
char sHello[12] = {"Hello C/C++"}; // 赋值
if( sHello[11] == '\0' ) // 比较

逻辑FALSE/false
虽然将FALSE/false 放在了一起,但是你必须清楚FALSE 和false 之间不只是大小写这么简单的差别。false/true 是标准C++ 语言里新增的关键字,而FALSE/TRUE 是通过#define 定义的宏,用来解决程序在C 与C++ 环境中的差异。以下是FALSE/TRUE 在windef.h 中的定义:
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif

换言之,FALSE/TRUE 是int 类型,而false/true 是bool 类型,两者是不一样的,只不过C++ 帮我们完成了相关的隐式转换,以至于我们在使用中没有任何感觉。bool 在C++ 里占用的是1 个字节,所以false 也只占用1 个字节。
其二进制表示如下:
false -> 0
FALSE -> 00000000 00000000 00000000 00000000

在C++ 中,推荐使用bool 类型的false/true,其使用方式如下:
bool isReady = false; // 赋值
if( isReady ) // 判断
如果不够细心,0 的多重性可能会让程序产生一些难以发现的Bug,比如:

// 把pSrc 指向的源字符串复制到pDes 指向的内存块
while(pSrc)
{
* pDes ++ = * pSrc ++;
}

正常情况下,当pSrc 指向的字符为字符串结束符'\0' 时,while 循环终止;但不幸的是,这里的条件写错了,while 终止条件变成了pSrc 指向地址0。结果while 循环写入到内存中了,直至程序崩溃。
正确的写法应该是:

while(*pSrc)
{

* pDes ++ = * pSrc ++;


}

 

你可能感兴趣的:(区分0的4种面孔)