首页 > 代码库 > 空指针的深入理解(C/C++)
空指针的深入理解(C/C++)
如果仅仅声明一个指针,而没有任何赋值,那么这个指针是野指针,它会指到VM的任何位置,碰到异常操作,比如对只读区写操作,就会引起硬件中断产生core,也就是通常的段错误。
良好的编程风格是将指针永远都可控,也就是这个指针的地址,程序可控,通常,对于不使用或初始的指针都将其地址置为0,这是约定俗成的,就如同,我们经常使用的进制一样,你非用一个别人都不用的进制表示数,那也随你,只是别人觉得怪而已。再比如,用free释放完指针后,相信大家都会将指针置成NULL或0,就是为了再使用这个指针时,便于判断。指针的地址为0,操作起来就非常方便,比较位操作等,都可对应到机器码,这也就体现了“高级汇编”的美誉。用NULL宏,仅仅是为了可读性,编译器会进行优化的。
对于将NULL定义成某个地址,然后进行比较,相对NULL为0地址,然后比较,性质是相同的,在执行过程中,如果重新定义的地址为可操作,可能会对程序的逻辑流程产生影响。
=========================================================================================
《C陷阱与缺陷》3.5节:
永远不能对空指针解引用!!!
如果将0赋给一个指针,绝对不能使用该指针指向的内容!!!
=========================================================================================
空指针的简单描述:
它 “与任何对象或函数的指针值都不相等”。也就是说, 取地址操作符 & 永远也不能得到空指针, 同样对 malloc() 的成功调用也不会返回空指针, 如果失败, malloc() 的确返回空指针, 这是空指针的典型用法:表示 “未分配”或者 “尚未指向任何地方”的指针。
========================================================================================
空指针和未初始化的指针:
空指针在概念上不同于未初始化的指针。空指针可以确保不指向任何对象或函数; 而未初始化指针则可能指向任何地方。
========================================================================================
空指针和 0
根据语言定义, 在指针上下文中的常数 0 会在编译时转换为空指针。
具体如下:
------------------------------------------------------------------------------------
可以使用未加修饰的0 需要显示的类型转换
------------------------------------------------------------------------------------
初始化 函数调用, 作用域内无原型
赋值 变参函数调用中的可变参数
比较
固定参数的函数调用且在作用域
内有原型
char *p = 0; execl("/bin/sh", "sh", "-c", "date", (char *)0);
if(p != 0)
-------------------------------------------------------------------------------------
注意:
if(p) 等价于 if(p != 0)。
这是一个比较上下文, 因此编译器可以看出 0 实际上是一个空指针常数, 并使用正确的空指针值。这里没有任何欺骗; 编译器就是这样工作的, 并为、二者生成完全一样的代码。
--*空指针的内部表达无关紧要。*--
=========================================================================================
NULL和空指针
作为一种风格, 很多人不愿意在程序中到处出现未加修饰的 0。因此定义了预处理宏 NULL (在 <stdio.h> 和其它几个头文件中) 为空指针常数, 通常是 0 或者((void *)0) 。希望区别整数 0 和空指针 0 的人可以在需要空指针的地方使用NULL。
--*使用NULL只是一种风格习惯;*--
预处理器把所有的NULL都还原回0, 而编译还是依照上文的描述处理指针上下文的 0。特别是, 在函数调用的参数里, NULL之前 (正如在 0 之前) 的类型转换还是需要。C 程序员应该明白, 在指针上下文中 NULL 和 0 是完全等价的, 而未加修饰的 0 也完全可以接受。
--*任何使用 NULL (跟 0 相对) 的地方都应该看作一种温和的提示, 是在使用指针。*--
程序员 (和编译器都) 不能依靠它来区别指针0和整数 0。特别是, 不能在需要 ASCII 空字符 (NUL) 的地方用NULL。如果有必要, 提供你自己的定义#define NUL ’\0’。
=======================================================================================
空指针的迷雾:
空指针的内部 (或运行期) 表达形式, 这可能并不是全零, 而且对不用的指针类型可能不一样。真正的值只有编译器开发者才关心。C程序的作者永远看不到它们。
理清楚几个概念
1,空指针,参见开头的定义,不同机器对于空指针的定义可能不同。
2,空指针常数,0 ,这个常数由编译器在运行阶段根据处理指针的上下文来转换为实际机器的空指针表达;
3,NULL宏,它只是空指针常熟的一种风格的定义,有好的提示使用的是指针。
4,ASCII空字符(NUL), 它的确是全零, 但它和空指针除了在名称上以外, 没有任何必然关系。
5,“空串” (null string), 它是内容为空的字符串 ("")。在 C 中使用空串这个术语可能令人困惑, 因为空串包括空字符 (’\0’),但不包括空指针。
冲出迷雾:
冲出这些迷惘的一个好办法是想象 C 使用一个关键字作为空指针常数。编译器要么在源代码没有歧义的时候把空指针常数转成适当类型的空指针, 或者有歧义的时候发出提示。C 语言的空指针常数
关键字是“0”, 这在多数情况下都能正常工作, 除了一个未加修饰的“0” 用在非指针上下文的时候, 编译器把它生成整数 0 而不是发出错误信息, 如果那个未加修饰的0是应该是空指针常数, 那么生成的程序不行。
简单的方法:
1. 当你在源码中需要空指针常数时, 用“0” 或“NULL”。
2. 如果在函数调用中 “0” 或 “NULL” 用作参数, 把它转换成被调函数需要的指
针类型(实际上这个2条件有点过于苛刻)