一.NULL指针
NULL,在C/C++常用来表示空指针,即指向地址为0的指针。
通常在指针初始化 或者 释放指针所指向空间后,将指针置为NULL,防治导致悬浮指针也使其表明自己未指向分配的空间。
这样看来指向NULL的指针仅仅如此?
当然我们也常常用一些小技巧来做一些很实用的事情比如,求Struct中某个变量的偏移位置:
#define VALUEOFFSET(sType, vName) (int)(&((sType *)NULL)->vName)
即使指向空的指针也能为我们程序做这么多事情,真有意思;而本人遇到的令人惊讶的问题,也和NULL指针扯上了关系。
二.NULL空类指针
先来看一段代码:
#include <iostream>
using namespace std;
class Base
{
public:
Base(){;}
void Suprise()
{
cout << "Suprise" << endl;
}
};
void main()
{
Base *pTest = NULL;
pTest->Suprise();
return;
}
在谨慎的阅读完这段代码后,或许能够做出正确的判断,但给人的第一感觉运行错误。
(直觉是人根据以往的经验和现场的环境做出的迅速的判断,慢慢的分析后得出的结果反而未必更加接近答案。)
但这次的确直觉错了,程序能够正常运行,并且能够很顺利的打印出"Suprise";
三.空类指针的函数调用分析
(1)仔细分析示例代码后,会发现Suprise()成员函数地址是不变的(非虚函数,无需动态绑定),在编译阶段根据pTest的指针类型就能得出Suprise()函数调用的地址;进行调用,汇编代码更加清晰得证明了这一点:
Base *pTest = NULL;
004119FE mov dword ptr [pTest],0
pTest->Suprise();
00411A05 mov ecx,dword ptr [pTest]
00411A08 call Base::Suprise (411032h)
如果是虚函数,我们这需要根据其指向的对象的虚表指针和虚函数偏移找到其相应的函数体入口,这个过程也成为动态绑定过程。
因为Suprise函数隐含了This指针,没有对成员变量进行操作,那么This指针为NULL也不会产生内存访问冲突错误。
void Suprise(Base * const this)