朴素的0值或者无类型的0值(void 0)
计算机语言中为了确定数据宽度(占用字节数)以及数据编码,一般都是有类型定义的,比如C语言中bool为8位逻辑值(单字节),int 为16位整数(双字节),long 为32位整数(4字节),float是32位浮点数(4字节),double为64位浮点数(8字节),等等。
因此,数据类型定义了数据宽度和数据编码,因此严格意义上说,一个16位整数的0与一个32位整数的0,以及浮点数的0都是不同的,原因是数据宽度不同,特别是浮点数的0不是绝对的0值,它可能是一个0.0000000000000001很小的数,但是有时候我们需要一个明确的通用的或者一般意义的0值来表示无效值,比如为了表示指针未被赋预有效地址,我们设置一个0值,为了防止代码有歧义,也为了可读性(一看就知道表示未定义指针),所以C或者C++中都使用一个特殊定义NULL表示无效值,其本质就是未定义具体数据类型的0值。
由于没有定义数据类型,因此也就不具有具体数据宽度和编码,当NULL赋值给16位变量时就是16位全0,当赋值给32位变量时,其值就是32个全0,也不会出现像浮点数那样产生精度误差。这就是虚类型的意义,任何编译器都认可这种约定,这样代码移植的时候不会因为软硬件环境改变而出现问题(CPU、编译器改变)。
你可以在任何编译器中,点击NULL右键查看定义。
这里稍微解释一下,上图高亮部分是表示C++,也就是如果当前语言是C++,则直接定义NULL为 0值,如果是其他(可能是C),则明确定义为 void 0,因为C++编译器会自动转换。#ifndef 宏命令表示:如果当前环境中其他模块还未定义NULL,这就定义它。
null指针是一个无类型指针,并且值为0。一个指针,拥有2个属性--地址值和指针类型。两者的作用是:1,地址值标识变量的首地址(32位系统下指针的地址值占4字节);2,指针类型告诉编译器,应该怎样进行接下来的数据访问(int型数组和float型数组是不同的;数组访问与结构体访问也是不同的;等等)。
大多数情况下为0
可以从头文件中看到其宏定义
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
#define offsetof(s,m) (size_t)&(((s *)0)->m)