代码之家  ›  专栏  ›  技术社区  ›  György Andrasek

空宏何时不是0?

  •  31
  • György Andrasek  · 技术社区  · 15 年前

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

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

    为了清楚起见,编辑:今天它扩展到 ((void *)0) , (0) (0L) . 然而,有些架构早就忘记了这一点,空扩展到另一个地址。有点像

    #ifdef UNIVAC
         #define NULL (0xffff)
    #endif
    

    我在找这样一台机器的例子。

    更新以解决问题:

    我的意思不是在当前标准的背景下提出这个问题,也不是用我不正确的术语来激怒人们。然而,我的假设得到了公认答案的证实:

    后来的模型使用了[blah],显然是为了迎合所有现存的写得不好的、做出错误假设的c代码。

    有关当前标准中空指针的讨论,请参见 this question .

    7 回复  |  直到 8 年前
        1
  •  32
  •   Brendan Long    12 年前

    c faq有一些具有非0空表示的历史机器的示例。

    The C FAQ List , question 5.17 :

    问:说真的,有没有真正使用非零零零零的机器 指针,或指向不同 类型?

    A:主50系列使用段07777,零点偏移0 指针,至少用于pl/i。以后的模型使用段0,偏移量0用于 c中的空指针,需要新的指令,如tcnp(test c空指针),显然是为了迎合所有现存的 写得不好的C代码,做出了错误的假设。年长的, 单词寻址的主要机器也因需要更大的 字节指针(char*'s)比字指针(int*'s)多。

    data general的eclipse mv系列在架构上有三个 支持的指针格式(字、字节和位指针),其中两种 由C编译器使用:char*和void*的字节指针,以及word 其他一切的指针。由于历史原因 从16位nova线到32位mv线的演变 指针和字节指针具有偏移量、间接寻址和环 世界上不同地方的保护位。传递不匹配的 指向函数的指针格式导致保护故障。 最后,mv c编译器添加了许多兼容性选项来尝试 处理指针类型不匹配错误的代码。

    一些Honeywell Bull大型机使用位模式06000 (内部)空指针。

    CDC Cyber 180系列有48位指针,由一个环组成, 分段和偏移。大多数用户(在环11中)都有空指针 0xb0000000000。这在旧的疾病预防控制中心的机器上很常见 使用所有一位字作为所有类型数据的特殊标志, 包括无效地址。

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

    symbolics lisp machine,一个标记的架构,甚至没有 传统的数值指针;它使用一对(基本上是 不存在句柄)作为C空指针。

    根据使用的“内存模型”,8086系列处理器(PC compatibles)可以使用16位数据指针和32位函数 指针,反之亦然。

    一些64位cray机器在 word;char*另外还使用16位中的一些位来表示 字内的字节地址。

        2
  •  3
  •   Jonathan Leffler    15 年前

    在C编译器中,它可以扩展到 ((void *)0) “(但不必这样做)。这对于C++编译器来说是行不通的。

    另请参见C FAQ,其中有一整章介绍 null pointers .

        3
  •  3
  •   paxdiablo    9 年前

    很久以前它被打成 ((void*)0) 或者其他一些特定于机器的方式,其中该机器没有使用全零位模式。

    一些平台(某些CDC或Honeywell机器)对空有不同的位模式(即, 所有的零)尽管ISO/ANSI在C90被批准之前修复了这个问题,通过指定 0 是源代码中正确的空指针, 不管 基本位模式的。从 C11 6.3.2.3 Pointers /4 (尽管如前所述,这一措辞一直追溯到C90):

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

        4
  •  2
  •   dan04    15 年前

    在gnu libio.h文件中:

    #ifndef NULL
    # if defined __GNUG__ && \
    (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8))
    #  define NULL (__null)
    # else
    #  if !defined(__cplusplus)
    #   define NULL ((void*)0)
    #  else
    #   define NULL (0)
    #  endif
    # endif
    #endif
    

    注意cpluplus上的条件编译。C++不能使用((空*)0),因为其更严格的指针铸造规则;标准要求NULL为0。c允许对null的其他定义。

        5
  •  1
  •   Jan Hudec    11 年前

    C编译器通常使用 ((void *)0) . 原因已经过去了 NULL 到具有可变参数的函数(或现在很少但仍然合法但没有原型的函数)。当指针大于int时, 0 只会被提升到 int 因此无法作为指针正确读取。

    C++编译器不能使用该定义,因为C++不允许隐式强制转换。 void * (铸造) 任何指针都是特殊大小写的)。但是C++ 11引入了新的关键字 nullptr 这是一个特殊的空指针常量 nullptr_t 类型隐式转换为任何指针类型,但不是数字。这既解决了变量参数问题,也解决了隐式强制转换,而且还解决了重载选择的更严重问题。( 因为显而易见的原因 int 指针1上的重载)。为旧的编译器定义这些是合法的,一些C++编译器在过去尝试过。

        6
  •  0
  •   John Saunders    15 年前

    在现代C语言中, void *pointer = 0; 是用来初始化“指针”使其不指向任何东西。是否通过将“指针”的位设置为全零来实现这一点是平台特定的。

    在过去,指针上下文中“0”的形式意义是不确定的。有必要将指针设置为平台视为“不指向任何地方”的实际值。例如,一个平台可能会选择一些固定地址,而这些地址永远不会得到映射到它的页面。在这种情况下,在旧的编译器中,平台可能已经定义了 NULL AS:

    #define NULL ((void*)0xFFFFF000)
    

    当然,今天,没有理由不把它定义为 ((void*)0) .

        7
  •  0
  •   AnT stands with Russia    8 年前

    NULL C中的宏扩展为实现定义的空指针常量。它可以是任何东西(因为它是实现定义的),但是在指针上下文中,效果总是一样的,就像它扩展为常量一样 0 .

    在标准C历史上从来没有一个时期 无效的 扩展到特定的 ,除非你考虑 (void *) 0 “不是0”。但是 (空洞*)0 对于 无效的 至今仍被广泛使用。