什么时候NULL宏不是0?

Gyö*_*sek 33 c macros null history

我隐约记得几年前读过这篇文章,但我在网上找不到任何参考.

你能给我一个NULL宏没有扩展到0的例子吗?

编辑清晰:今天,它扩展为((void *)0),(0)(0L).但是,有些架构早已被遗忘,而这种情况并非如此,并且NULL扩展到了不同的地址.就像是

#ifdef UNIVAC
     #define NULL (0xffff)
#endif
Run Code Online (Sandbox Code Playgroud)

我正在寻找这样一台机器的例子.

更新以解决问题:

我不是在现行标准的背景下提出这个问题,也不是用不正确的术语来扰乱人们.但是,我接受的答案证实了我的假设:

后来的模型使用了[blah],显然是对所有现存的写得不好的C代码的反应,这些代码做出了错误的假设.

有关当前标准中的空指针的讨论,请参阅此问题.

jan*_*nks 32

C FAQ具有一些具有非0 NULL表示的历史机器的示例.

来自C FAQ列表,问题5.17:

问:说真的,有任何实际的机器真的使用非零空指针,还是指向不同类型的指针的不同表示?

答:Prime 50系列使用了段07777,空指针的偏移量为0,至少对于PL/I. 后来的模型使用了段0,偏移0用于C中的空指针,需要新的指令,如TCNP(测试C空指针),显然是[脚注]所有现存的写得不好的C代码的错误,这些代码做出了错误的假设.较旧的,字寻址的Prime机器也因为需要比字指针(int*)更大的字节指针(char*)而臭名昭着.

Data General的Eclipse MV系列有三种架构支持的指针格式(字,字和位指针),C编译器使用其中两种:char*和void*的字节指针,以及其他所有字的指针.由于历史原因在从16位Nova线演变32位MV线期间,字指针和字节指针在字中的不同位置具有偏移,间接和环保护位.将不匹配的指针格式传递给函数会导致保护错误.最终,MV C编译器添加了许多兼容性选项,以尝试处理具有指针类型不匹配错误的代码.

一些霍尼韦尔 - 布尔大型机使用位模式06000作为(内部)空指针.

CDC Cyber​​ 180系列具有48位指针,包括环,段和偏移.大多数用户(在环11中)具有0xB00000000000的空指针.在旧的CDC补充机器上,通常使用全1位字作为各种数据的特殊标志,包括无效地址.

旧的HP 3000系列使用不同的字节地址寻址方案而不是字地址; 像上面的几台机器一样,它使用char*和void*指针的不同表示而不是其他指针.

Symbolics Lisp Machine是一种标记架构,甚至没有传统的数字指针; 它使用该对(基本上是一个不存在的句柄)作为C空指针.

根据使用的"内存模型",8086系列处理器(PC兼容机)可能使用16位数据指针和32位函数指针,反之亦然.

一些64位Cray机器在一个字的低48位中表示int*; char*另外使用高16位中的一些来指示字内的字节地址.

  • 在C源代码中,NULL宏仍然是一个求值为0的整型常量表达式或者它的(void*)强制转换.结果指针值可能具有不为0的表示,但这并不意味着源代码可以假设它将是0xffff或类似的东西. (5认同)
  • 对不起,但答案完全是假的.C FAQ中给出的示例是具有非零*空指针值*的机器的示例.问题是关于非零"NULL",即关于非零*空指针常量*.空指针值和空指针常量是两个完全不同的东西.答案是彼此错误的,这是一个相当普遍的错误(一个新手的错误,我应该补充). (2认同)
  • 问题是“NULL”扩展到什么。这个答案与“NULL”扩展成的内容完全无关。然而,问题的作者说“正是我正在寻找的”(???)。显然作者很困惑(误解了 NPC 和 NPV 之间的区别,正如我上面所说的)。 (2认同)

pax*_*blo 6

很久以前,它被键入为((void*)0)或某种其他特定于机器的方式,该机器不使用全零位模式。

某些平台(某些 CDC 或 Honeywell 机器)对 NULL 有不同的位模式(即不是全零),尽管 ISO/ANSI 在批准 C90 之前通过指定这0是源代码中正确的 NULL 指针来修复这一点,无论底层位模式。来自C11 6.3.2.3 Pointers /4(不过,正如前面提到的,这个措辞可以一直追溯到 C90):

具有 value 的整型常量表达式0,或转换为 type 的此类表达式void *,称为空指针常量。