这个问题困扰了我一段时间。我从未见过 NULL 的不同定义,它总是
#define NULL ((void *) 0)
是否有任何架构不同地定义了 NULL,如果是这样,为什么编译器不为我们声明这个?
这个问题困扰了我一段时间。我从未见过 NULL 的不同定义,它总是
#define NULL ((void *) 0)
是否有任何架构不同地定义了 NULL,如果是这样,为什么编译器不为我们声明这个?
WhozCraig将这些评论写到一个现已删除的答案中,但它可以提升为完整答案(这就是我在这里所做的)。他指出:
有趣的注释:AS/400 是一个非常独特的平台,任何无效指针都被认为等同于
NULL
. 他们用来做这件事的机制简直太棒了。从这个意义上说,“有效”是任何 128 位指针(平台对所有内容都使用 128 位线性地址空间),其中包含由已知可信指令集获得的“值”。很难相信,int *p = (int *)1; if (p) { printf("foo"); }
不会在该平台上打印“foo”。分配给 p 的值不受源信任,因此被认为是“无效的”,因此等同于NULL
.坦率地说,它的工作原理令人吃惊。进程映射的虚拟地址空间中的每个 16 字节段落在进程范围的位图中都有一个对应的“位”。所有指针必须驻留在这些段落边界之一上。如果该位被“点亮”,则相应的指针是从受信任的来源存储的,否则它是无效的并且等效于 NULL。对 malloc、指针数学等的调用都在确定该位是否被点亮时被仔细检查。正如你可以想象的那样,将指针放在结构中会给结构打包的想法带来一个全新的伤害世界。
这被标记为 community-wiki(这不是我的答案——我不应该得到荣誉)但如果 WhozCraig 写了他自己的答案,它可以被删除。
这表明存在具有有趣指针属性的真实平台。
有些平台#define NULL ((void *)0)
不是通常的定义;在某些平台上,只要编译器理解它,它就可以是0
、 在其他平台上0L
或其他适当的值。0ULL
C++ 不喜欢((void *)0)
作为定义;标头与 C++ 交互的系统可能不使用 void 指针版本。
我在一台机器上学习了 C,其中char *
给定内存位置的int *
地址表示与同一内存位置的地址不同。这是在前几天void *
,但这意味着您必须malloc()
正确声明(char *malloc();
也没有原型),并且您必须将返回值显式转换为正确的类型,否则您会得到核心转储。感谢 C 标准(尽管有问题的机器是 ICL Perq(来自三河公司的标志性硬件)在定义标准时已在很大程度上被取代)。
C 2011 标准,在线草案
6.3.2.3 指针
...
3 值为 0 的整数常量表达式,或转换为 type 的这种表达式void *
,称为空指针常量。66)如果将空指针常量转换为指针类型,则生成的指针(称为空指针)保证与指向任何对象或函数的指针不相等。
66) 宏NULL
在<stddef.h>
(和其他头文件)中定义为空指针常量;见 7.19。
宏 NULL
总是被定义为一个零值的常量表达式;它可以是一个赤裸裸的 0,或 0 转换为void *
,或其他一些计算为 0 的整数表达式。就您的源代码而言,NULL
将始终计算为 0。
翻译代码后,任何出现的空指针常量(0、...NULL
等)都将替换为底层架构用于空指针的任何内容,该空指针可能是也可能不是 0 值。
In the dark ages before ANSI-C the old K&R C had many different implementations on hardware that would be considered bizarre today. This was before the days of VM when machines were very "real". Addresses of zero were not only just fine on these machines, an address of zero could be popular... I think it was CDC that sometimes stored the system constant of zero at zero (and did strange things happen if this was set non-zero).
if ( NULL != ptr ) /* like this */ if ( ptr ) /* never like this */
The trick was finding address you could safely use to indicate "nothing" as storing things at the end of memory was also popular, which ruled out 0xFFFF on some architectures. And these architectures tended to use word addresses rather than byte addresses.
我不知道这个问题的答案,但我在猜测。在 C 中,您通常会执行很多 malloc,因此需要对返回的指针进行很多测试。由于 malloc 在失败时返回 void *,尤其是 (void *)0,因此为了测试 malloc 是否成功,定义 NULL 是很自然的事情。由于这非常重要,其他库函数也使用 NULL(或 (void *)0),例如 fopen。实际上,所有返回指针的东西。
因此,这里没有理由在语言级别定义 this - 它只是一个特殊的指针值,可以由这么多函数返回。