NULL,NUL,'\0'和0

    在最近学习中,在网上偶然间看到了这样一段代码,大致意思如下:

    for( i = 0; s[i] != NULL ; i++)
    printf(“%c”,s[i]);

     当时心中顿生疑惑, str 明明是一个字符数组,最后应该是以 ’\0’ 为结束标志才是,怎么可能来用 NULL 进行判断呢?加上最近看到的各种奇葩的类型,什么 0 (void *)0 NUL ,立感混乱。于是在网上查了一下这些 兄弟们 ,整理出来。虽然自己还分得清它们各用在什么场合,但其中道理还真是不知道。

    先从简单的开始入手吧。

    一、’\0’与NULL

    就是上面的例子,自己写了一段小程序来进行试验:

#include <stdio.h>
#include <string.h>
                                                                                
int main( int argc,char *argv[] )
{
    int i = 0;
    char str[10];
    strcpy(str,"hello");
    while(str[i] != NULL)
    {   
        printf("%c",str[i]);
        i++;
    }   
    printf("\n");
    return 0;
}

    在用 gcc 进行编译时,会报出来一个警告:

    警告: 比较指针和整数 [默认启用]

    但是仍可以执行,而且运行结果完全正确:          

hello
    用clang编译器进行编译时,它给出了更为详细的警告:

warning: comparison between pointer and integer ('int' and 'void *')
    比较指针与整数,不用说,其中的(void *)型肯定是NULL了。由此可见,NULL是一个无类型指针,并且其值为0。它的作用就是用于指示一个指针为空,即什么都不指。


    二、0与NULL

    在标准宏定义头文件stddef.h中,有关于NULL的如下定义:

#define NULL
#define __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
#interface NULL 0
    从前还从没有想过0与NULL间的关系,不过在看《Linux编程实战》一书中,看到线程控制一章时,好多概念不好理解,便到网上去找代码看,竟看到好多版本把pthread_create函数中的 NULL写成(void *)0.做了下面这个小实验:

#include <stdio.h>

int main( int argc,char *argv[] )
{
    if( 0 == NULL)
        printf("0 == NULL\n");
    return 0;
}
    本以为编译时会同样报出来一个不能比较指针与整数的警告,结果用gcc却顺利编译通过,加上-Wall也能编译通过,就连一向严谨的clang也顺利编译通过。而且,最重要的是,它竟然打印出下面的结果来:

0 == NULL
    在百度百科中看到下面这段话,觉得还比较好来解释:

    NULL与0有着扯不断理还乱的关系,其实不那么高深。0本身有着一些原生的特性诸如:起始,没有,正负的分界线,0/1中的0还可以表示否定。NULL正需要这些特性中的一部分。 我们只需要清楚NULL的本质,并在合理的地方才加以利用而非滥用。譬如我想做一个比较某个整数i是否为0,难道写成i==NULL会比i==0更酷一点吗?

    的确,研究0与NULL的关系也没什么必要,估计也没有人会把i=0写成i=NULL。


    三、NUL

    不是在咬文嚼字,这货我确实见过,确定不是NULL。虽然只比NULL少了一个‘L’,但是意义却大不相同。第一次见到这个奇怪的东西是在《C和指针》一书中。原文是这样说的:

    “字符串就是一串以NUL字节结尾的字符。NUL是作为字符串终止符,它本身并不是字符串的一部分”

    字符串终止符?!那不就是'\0'嘛!这里怎么说成了NUL?

    还好书下还有这样一段注释,看了之后恍然大悟:

    “NUL是ASCII字符集中'\0'的名字,它的字节模式为全0。NULL指一个其值为0的指针。它们都是整型值,其值也相同。所以它们是可以互换使用。然而,你还是应该使用适当的常量,因为它能告诉阅读程序的人不仅使用0这个值,而且告诉他们使用这个值的目的。”


    但是还是要注意一点,NUL在C/C++中是没有定义的,如果要使用还需要自己宏定义#define NUL '\0'。而这一点在《C与指针》一书竟没有提到,感觉会给读者造成一定的误解。不过个人觉得还是用'\0'来的更直接明白些,'\0'就是'\0',如果写成NUL,反倒更加难以理解了,弄不好还会和NULL不小心用混。


    在google中还找到了一些关于这些符号的比较权威些的解释:

    

    NULL is a macro defined in several standard headers, 0 is an integer constant, '\0' is a character constant, and nul is the name of the character constant. All of these are *not* interchangeable:

    NULL is to be used for pointers only since it may be defined as ((void *)0), this would cause problems with anything but pointers.

    0 can be used anywhere, it is the generic symbol for each type's zero value and the compiler will sort things out.

    '\0' should be used only in a character context.

    nul is not defined in C or C++, it shouldn't be used unless you define it yourself in a suitable manner, like:

    #define nul '\0'

    其中这句话,“All of these are not interchangeable”,看来也不能说的这样绝对,至少在本文开关的例子中,'\0'和NULL就成功地互用了。如果这样来说应该更准确些:不建议去互用这些符号——原因就像《C和指针》里那样说,它能告诉阅读程序的人不仅使用0这个值,而且告诉他们使用这个值的目的:

    NULL就是使一个指针“空悬”;

    '\0'就是用来标志字符串结束;

    0就是0。

    正所谓,到什么山,唱什么歌,毕竟用NULL来当字符串结束标志,用0来让指针空悬,不是一件看起来很舒服的事,虽然它们可以正常编译通过。




    

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值