改善C++ 程序的150个建议学习之建议1:区分0的4种面孔
2013-09-09 13:52
274 查看
建议1:区分0的4种面孔
0在C/C++语言中绝对是一个多面手,它扮演着多样的角色,拥有着多种面孔。总结起来包括以下几种角色:整型0、空指针NULL、字符串结束标志 '\0'、逻辑FALSE/false,不同的角色适用于不同的情形,下面我们按照上述顺序一一介绍。
整型0
这是我们最熟悉的一个角色。作为一个int类型,整型0占据32位的空间,其二进制表示为:
A return statement in main has the effect of leaving the main function (destroying any objects with automatic
storage duration) and calling exit with the return value as the argument. If control reaches the end of main
without encountering a return statement, the effect is that of executing return 0.— ISO C++03 3.6.1 Main
function.
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时会进行一次强制转型。我想之所以创造出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循环写入到内存中了,直至程序崩溃。正确的写法应该是:
// 把pSrc指向的源字符串复制到pDes指向的内存块中
while(*pSrc)
{
* pDes ++ = * pSrc ++;
}
请记住:由于0存在多种面孔,容易让不细心的程序员产生混乱。唯一的解决办法就是在使用0的时候小心一点,再小心一点。
0在C/C++语言中绝对是一个多面手,它扮演着多样的角色,拥有着多种面孔。总结起来包括以下几种角色:整型0、空指针NULL、字符串结束标志 '\0'、逻辑FALSE/false,不同的角色适用于不同的情形,下面我们按照上述顺序一一介绍。
整型0
这是我们最熟悉的一个角色。作为一个int类型,整型0占据32位的空间,其二进制表示为:
A return statement in main has the effect of leaving the main function (destroying any objects with automatic
storage duration) and calling exit with the return value as the argument. If control reaches the end of main
without encountering a return statement, the effect is that of executing return 0.— ISO C++03 3.6.1 Main
function.
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时会进行一次强制转型。我想之所以创造出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循环写入到内存中了,直至程序崩溃。正确的写法应该是:
// 把pSrc指向的源字符串复制到pDes指向的内存块中
while(*pSrc)
{
* pDes ++ = * pSrc ++;
}
请记住:由于0存在多种面孔,容易让不细心的程序员产生混乱。唯一的解决办法就是在使用0的时候小心一点,再小心一点。
相关文章推荐
- 改善C++ 程序的150个建议学习之建议27:区分内存分配的方式
- 改善C++ 程序的150个建议学习之建议18:正确区分void与void*
- 改善C++ 程序的150个建议学习之建议29:区分new的三种形态
- 改善C++ 程序的150个建议学习之建议3:对表达式计算顺序不要想当然
- 改善C++ 程序的150个建议学习之建议13:掌握变量定义的位置与时机
- 改善C++ 程序的150个建议学习之建议20:使用memcpy()系列函数时要足够小心
- 改善C++ 程序的150个建议学习之建议30:new内存失败后的正确处理
- 改善C++ 程序的150个建议学习之建议34:用智能指针管理通过new创建的对象
- 改善C++ 程序的150个建议学习之建议14:小心typedef使用中的陷阱
- 改善C++ 程序的150个建议学习之建议35:使用内存池技术提高内存申请效率与性能
- 改善C++ 程序的150个建议学习之建议21:尽量用new/delete代替malloc/free
- 改善C++ 程序的150个建议学习之建议15:尽量不要使用可变参数
- 改善C++ 程序的150个建议学习之建议4:小心宏#define使用中的陷阱
- 改善C++ 程序的150个建议学习之建议26:用引用代替指针
- 改善C++ 程序的150个建议学习之建议0:不要让main函数返回void
- 改善C++ 程序的150个建议学习之建议22:灵活地使用不同风格的注释
- 改善C++ 程序的150个建议学习之建议6:明晰逗号分隔表达式的奇怪之处
- 改善C++ 程序的150个建议学习之建议16:慎用goto
- 改善C++ 程序的150个建议学习之建议17:提防隐式转换带来的麻烦
- 改善C++ 程序的150个建议学习之建议23:尽量使用C++标准的iostream