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编译的程序,
访问时会出现异常,其他的编译器不知道会怎么样。
时间: 2024-10-27 14:03:47

NULL指针分析的相关文章

SQL Server-聚焦NOT IN VS NOT EXISTS VS LEFT JOIN...IS NULL性能分析(十八)

前言 本节我们来综合比较NOT IN VS NOT EXISTS VS LEFT JOIN...IS NULL的性能,简短的内容,深入的理解,Always to review the basics. NOT IN.NOT EXISTS.LEFT JOIN...IS NULL性能分析 我们首先创建测试表 USE TSQL2012 GO CREATE SCHEMA [compare] CREATE TABLE [compare].t_left ( id INT NOT NULL PRIMARY KE

20150430 调试分析之 根据内核报错信息PC指针分析错误

20150430 调试分析之 根据内核报错信息PC指针分析错误 2015-04-30 Lover雪儿 大家写驱动的时候不知道有没有发现,当我们驱动写错了,发生内核奔溃时,会打印一大堆的报错信息, 如果再返回我们的程序中一行一行代码的检查,既耗费时间,并且有些逻辑上的错误,我们是很难看的出来的, 那我们能不能再这一大堆的报错信息中发现问题的所在呢? 此处我们来模拟一个错误,还是沿用上一篇文章中的驱动代码err_led.c的驱动程序中的代码修改错误,当然大家用其他的驱动代码做测试也可以. 博客地址:

Null指针

C++ Null 指针 C++ 指针 C++ 指针 在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯.赋为 NULL 值的指针被称为空指针. NULL 指针是一个定义在标准库中的值为零的常量.请看下面的程序: #include <iostream> using namespace std; int main () { int *ptr = NULL; cout << "ptr 的值是 " << ptr

C++教程:NULL 指针、零指针、野指针

C++教程:NULL 指针.零指针.野指针 1. 空指针.NULL指针.零指针 1.1什么是空指针常量 0.0L.".3 – 3.0 * 17 (它们都是"integer constant expression")以及 (void*)0 (我觉得(void*)0应该算是一个空指针吧,更恰当一点)等都是空指针常量(注意 (char*) 0 不叫空指针常量,只是一个空指针值).至于系统选取哪种形式作为空指针常量使用,则是实现相关的.一般的 C 系统选择 (void*)0 或者 0

C语言中字符数组和字符串指针分析

这几天搞Unix上的C程序,里面用到了很多字符数组和字符串指针,我记得在学完C语言后相当一段时间里,对指针这个东西还是模模糊糊,后来工作也没怎么 用到过C,虽然网上这类的文章也有很多,还是决定自己在这做个小总结,也算加深下自己的印象,写了下面的测试程序: #include <stdio.h> int main(int argc, char *argv[]){ char day[15] = "abcdefghijklmn";  char* strTmp = "opq

如何处理android程序变为后台程序,系统回收资源,再次打开时,程序因为null指针等崩溃

home键等原因,程序会变为后台程序,系统会更具需要,可能回收资源,再打开时候,就会因为资源回收,再调用oncreate,没有Intent参数而导致程序崩溃.   这种情况,我们可以处理的方式有两种,一是用: @Override     protected void onSaveInstanceState(Bundle outState) {      // TODO Auto-generated method stub      super.onSaveInstanceState(outSta

NULL指针区域(NULL定义为0-65535之间的任何数都可以)

NULL指针区域0x00000000-0x0000FFFF:65535字节 这个区域的作用是用来帮助程序员发现内存分配失败后未检查就使用的错误.比如使用malloc分配内存失败,返回NULL,而又未做检查直接使用,如例子:就会产生内存非法访问的错误,提示程序员int *piNum = (int*)malloc(sizeof(int));int *piNpm = 5; 以前一直不理解NULL的意思,一直以为就是个0,现在来看,这个空指针是有他的道理的,是利用了windows的内存管理机制做的一个内

解引用NULL指针

一般导致程序崩溃的最重要原因之一就是试图解引用NULL指针.正如上几篇文章中所说的,智能指针RefCountPtr和ScopedPtr提供了运行时的诊断.但是,并不是所有的指针都是拥有某个对象所有的智能指针.因此为了对试图解引用一个不具有对象所有权的指针的行为进行诊断,引入一种并不删除它所指向的对象的"半智能"指针.例如,如下代码示例: template <typename T> class Ptr { public: explicit Ptr(T* p = NULL) :

NULL指针、零指针、野指针

1. 空指针.NULL指针.零指针 1.1什么是空指针常量 0.0L.'\0'.3 - 3.0 * 17 (它们都是"integer constant expression")以及 (void*)0 (我觉得(void*)0应该算是一个空指针吧,更恰当一点)等都是空指针常量(注意 (char*) 0 不叫空指针常量,只是一个空指针值).至于系统选取哪种形式作为空指针常量使用,则是实现相关的.一般的 C 系统选择 (void*)0 或者 0 的居多(也有个别的选择 0L):至于 C++