解析C语⾔中空指针、空指针常量、NULL0的详解
[6.3.2.3-3] An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.
这⾥告诉我们:0、0L、'\0'、3 - 3、0 * 17 (它们都是“integer constant expression”)以及 (void*)0 (tyc:我觉得(void*)0应该算是⼀个空指针吧,更恰当⼀点)等都是空指针常量(注意 (char*) 0 不叫空指针常量,只是⼀个空指针值)。⾄于系统选取哪种形式作为空指针常量使⽤,则是实现相关的。⼀般的 C 系统选择 (void*)0 或者 0 的居多(也有个别的选择 0L);⾄于C++ 系统,由于存在严格的类型转化的要求,void* 不能象 C 中那样⾃由转换为其它指针类型,所以通常选 0 作为空指针常量(tyc: C++标准推荐),⽽不选择 (void*)0。
[6.3.2.3-3] If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.
因此,如果 p 是⼀个指针变量,则 p = 0;、p = 0L;、p = '\0';、p = 3 - 3;、p = 0 * 17; 中的任何⼀种赋值操作之后(对于 C 来说还可以是 p = (void*)0;), p 都成为⼀个空指针,由系统保证空指针不指向任何实际的对象或者函数。反过来说,任何对象或者函数的地址都不可能是空指针。(tyc: ⽐如这⾥的(void*)0就是⼀个空指针。把它理解为null pointer还是null pointer constant会有微秒的不同,当然也不是紧要了)
[6.3.2.3-Footnote] The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant
即 NULL 是⼀个标准规定的宏定义,⽤来表⽰空指针常量。因此,除了上⾯的各种赋值⽅式之外,还可以⽤ p = NULL; 来使 p 成为⼀个空指针。(tyc:很多系统中的实现:#define NULL (void*)0,与这⾥的“a null pointer constant”并不是完全⼀致的)
标准并没有对空指针指向内存中的什么地⽅这⼀个问题作出规定,也就是说⽤哪个具体的地址值(0x0 地址还是某⼀特定地址)表⽰空指针取决于系统的实现。我们常见的空指针⼀般指向 0 地址,即空指针的内部⽤全 0 来表⽰(zero null pointer,零空指针);也有⼀些系统⽤⼀些特殊的地址值或者特殊的⽅式表⽰空指针(nonzero null pointer,⾮零空指针),具体请参见C FAQ。
幸运的是,在实际编程中不需要了解在我们的系统上空指针到底是⼀个 zero null pointer 还是 nonzero null pointer,我们只需要了解⼀个指针是否是空指针就可以了——编译器会⾃动实现其中的转换,为我们屏蔽其中的实现细节。注意:不要把空指针的内部表⽰等同于整数 0 的对象表⽰——如上所述,有时它们是不同的。
这可以通过与空指针常量或者其它的空指针的⽐较来实现(注意与空指针的内部表⽰⽆关)。例如,假设 p 是⼀个指针变量,q 是⼀个同类型的空指针,要检查 p 是否是⼀个空指针,可以采⽤下列任意形式
之⼀——它们在实现的功能上都是等价的,所不同的只是风格的差别。
if ( p == 0 )
if ( p == '\0' )
空值是指零长度的字符串if ( p == 3 - 3 )
if ( p == NULL ) /* 使⽤ NULL 必须包含相应的标准库的头⽂件 */
if ( NULL == p )
if ( !p ) <---------------(这⾥和下⾯的if(p)都被专门说过⼀次,null定义不⼀定是0.这⾥如果贸然使⽤!p会很危险的.所以这种写法不能被提倡)
if ( p == q )
...
if ( p != 0 )
if ( p != '\0' )
if ( p != 3 - 3 )
if ( p != NULL ) /* 使⽤ NULL 必须包含相应的标准库的头⽂件 */
if ( NULL != p )
if ( p )
if ( p != q )
...
这个问题等同于:如果 p 是⼀个指针变量,那么
memset( &p, 0, sizeof(p) ); 和 p = 0;
答案是否定的,虽然在⼤多数系统上是等价的,但是因为有的系统存在着“⾮零空指针” (nonzero null pointer),所以这时两者不等价。由于这个原因,要注意当想将指针设置为空指针的时候不应该使⽤ memset,⽽应该⽤空指针常量或空指针对指针变量赋值或者初始化的⽅法。
可以定义⾃⼰的 NULL 的实现吗?兼答"NULL 的值可以是 1、2、3 等值吗?"类似问题
[7.1.3-2] If the program declares or defines an identifier in a context in which it is reserved (other than as allowed by 7.1.4), or defines a reserved identifier as a macro name, the behavior is undefined.
NULL 是标准库中的⼀个符合上述条件的 reserved identifier (保留标识符)。所以,如果包含了相应的标准头⽂件⽽引⼊了NULL 的话,则再在程序中重新定义 NULL 为不同的内容是⾮法的,其⾏为是未定义的。也就是说,如果是符合标准的程序,其 NULL 的值只能是 0,不可能是除 0 之外的其它值,⽐如 1、2、3 等。
malloc 函数是标准 C 规定的库函数。在标准中明确规定了在其内存分配失败时返回的是⼀个 “null pointer”(空指针):[7.20.3-1] If the space cannot be allocated, a null pointer is returned.
对于空指针值,⼀般的⽂档(⽐如 man)中倾向于⽤ NULL 表⽰,⽽没有直接说成 0。但是我们应该清楚:对于指针类型来说,返回 NULL 和返回 0 是完全等价的,因为 NULL 和 0 都表⽰ “null pointer”(空指针)。(tyc:⼀般系统中⼿册中都返回NULL,那我们就⽤NULL吧)
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论