NULL指针分析

最近在查看同事写的一段程序时,发现里边有一个函数大概如下:
void  example(uint8  *pData)
{
     ...
      if(NULL == *pData)
          return;
     while(*pData != NULL)
     {
     ...
     }
     ...
}

第一眼看去感觉红色部分写的没有什么,当看到while时,
感觉第一句有些多余,
没有必要这样判断,当*pData == NULL时while就进不去,
但是想到这里是第一次判断pData,于是估计当时同事是想写if(NULL == pData),笔误写作了if(NULL == *pData).
于是我跟同事提出这里是一个bug,有可能会造成程序读取NULL指针,引发异常。
同事看后,说没事,就是判断*pData == NULL。
如果说是判断*pData,就没有必要用第一个if。
最早理解的是不能对NULL指针进行操作,所以要判断pData非空。

因为最早是在《程序员成长计划》中,看到对于传入指针参数的非NULL判断的重要性,同时向NULL指针写入数据会出错的。
所以我建议最好不要这样操作。
同事说,NULL指针怎么就不能读呢?
这个问题确实难倒了我,确实如果NULL指针允许读,也就不会异常了。(现在想到,这也是不可能的,虽然程序没有引发异常,但是这是在NULL处开始读值,读出的值也会影响操作的,因为这个指针,如果是正常操作,不会传入NULL进来,这比直接异常还要可怕,因为将bug的地方引到了别处,反而会提高找出bug的难度。还不如直接异常,下边关于结构的的NULL就有这个问题)
对于在MCU中,虽然没有操作系统的管理,但是对于NULL处的一般是存放中断向量表的起始地址的地方,尤其是上电复位的第一个跳转指令。所以这一段地址,程序读取也是没有意义的,所以对于C语言使用判断指针为NULL,也是可以的。但是会不会引发异常,我不确定,但是至少会造成程序运行不正常。

空指针在C/C++中占有特殊的地址,通常它是用来判断一个指针的有效性的。空指针一般定义为0,。现代操作系统都会保留从0开始的一块内存,至于这块内存有多大,是不同的操作系统而定。一旦程序试图访问这块内存,系统就会触发一个异常/信号。
操作系统为什么要保留一块内存,而不是仅仅保留一个字节的内存呢?这是因为一般内存管理都是按页进行管理的,根本就无法仅仅保留一个字节, 而至少要保留一个页面。保留一块内存也有额外的好处,可以检查注入p=NULL,p[1]之类的内存错误。
在一些嵌入式系统中(如ARM7,Cortex-M3),从零开始的一块内存是用来安防中断向量的,没有MMU的保护,直接访问这块内存好像不会引发异常。不过这块内存是代码的,而不是程序中有效变量的地址,所以用空指针来判断指针的有效性任然是可行的。
《程序员成长计划》写的又好又快的秘诀。

不过,
对于在Linux系统下,关于NULL指针肯定是不允许读的,因为操作系统的text端起始于0x08048000,对于0~0x08048000之间的约128M空间,用来判断NULL指针内容。
在Linux系统下,IA-32系统起始于0x08048000 (ARM9内核系统中是0x8000),在text段的起始地址与最低的可用地址之间有大约128M的间距,用于捕获NULL指针。不允许用户空间访问。
《深入Linux内核架构》

NULL指针的定义
Pointers and integers are not interchangeable. Zero is the sole exception: the constant zero may be assigned to a pointer, 
and a pointer may be compared with the constant zero. 
The symbolic constant NULL is often used in place of zero, 
as a mnemonic to indicate more clearly that this is a special value for a pointer. 
NULL is defined in <stdio.h>.
《the c programming language》  page 92 

还有一些分析没有做。
对于结构体指针变量为空时对其成员的访问是否异常?
曾经看到一个是说由编译器决定,
这个在自己的电脑上用gcc编译的程序,
访问时会出现异常,其他的编译器不知道会怎么样。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值