【问题标题】:Does (size_t)((char *)0) ever not evaluate to 0?(size_t)((char *)0) 是否永远不会评估为 0?
【发布时间】:2023-03-09 12:15:01
【问题描述】:

根据"Why subtract null pointer in offsetof()?" 中的回复(以及我对K&R 的阅读),C 标准不需要(size_t)((char *)0) == 0。不过,我从未见过将空指针转换为整数类型的情况会评估为其他任何值。

如果有(size_t)((char *)0) != 0的编译器或场景,是什么?

【问题讨论】:

    标签: c compiler-construction pointers casting standards-compliance


    【解决方案1】:

    好吧,如您所知,给定类型的空指针的物理表示不一定是全零位模式。当您强制将指针(任何指针)值转换为整数类型时,结果是实现定义的,但通常(这就是意图)指针的数值 - 数字地址 - 如果可能的话保持不变。这意味着,如果在给定平台上,char * 类型的空指针由0xBAADF00D 模式(例如)表示,则上述表达式的计算结果为0xBAADF00D,而不是零。当然,为此您需要一个具有非零空指针的平台。我个人从未使用过这样的平台,尽管我听说过很多这样的真实平台(比如,在嵌入式平台领域,这并不罕见)。

    此外,作为补充说明,不同类型的空指针值可以具有不同的物理表示,这意味着理论上您可以从(size_t) ((int *) 0)(size_t) ((char *) 0)(size_t) ((double *) 0) 获得不同的值。但这将是一个相当奇特的情况,尽管从抽象 C 语言的角度来看是完全可能的。

    附:阅读here(C 常见问题解答),了解一些具有非零空指针的实际平台示例。

    【讨论】:

    • 我理解理论上的论点(你解释得很好),但我正在寻找实际系统的示例,其中将空指针转换为整数会导致实践中的非零值。跨度>
    • @Bruce Christensen:请参阅 P.S. 中的 C 常见问题解答链接
    • 有趣。看起来一些古老的系统使用非零位表示,但常见问题解答中没有现代示例。似乎可以肯定的是,运行 Linux 的系统都不会使用非零表示,否则它的 offsetof() 实现会中断(请参阅google.com/codesearch/p?hl=en#huut-anHVuo/anonymous/kernel/v2.6/…)。
    • @Bruce Christensen:标准库实现是特定于平台的。它不需要在源代码级别具有可移植性。因此,如果在某些平台(Linux 或非 Linux)上,空指针不为零,则该平台的 offsetof 的实现会有所不同。就这么简单。
    • 我在一台机器(编译 C 代码)上工作,它的 0xFFFFFFFF 为空(霍尼韦尔公牛 DPS7)。当时对我来说这似乎很自然(每台机器都有一个地址 0,所以让它“非法”真的很奇怪)
    【解决方案2】:

    C 标准对空指针运行时表示的唯一要求是 (6.3.2.3/3 "Pointers"):

    ...生成的指针,称为空指针,保证与指向任何对象或函数的指针不相等。将空指针转换为另一种指针类型会产生该类型的空指针。

    任何两个空指针应该比较相等。

    不过,您的问题很有趣。就个人而言,我不知道不使用运行时值 0 来表示空指针的平台。但是,标准并不要求它,所以如果您可以避免代码中的假设,为什么不呢?

    我也对任何知道使用非零运行时值作为空指针的系统的人感兴趣。

    【讨论】:

      【解决方案3】:

      C99 标准规定,当您将整数值 0 转换为指针时,它会变成 NULL 指针。所以((char*)0) 是一个空指针。 NULL 指针不需要具有0 的实际二进制表示。例如,它可以是0x12345678

      C 标准进一步指出,当您将 NULL 指针转换为整数常量时,结果是“实现定义的”。实际上,编译器所做的只是将指针的数值转换为相应的整数值,正如 AndreyT 所说。所以在上面的例子中,整数值最终可能是0x12345678,尽管从技术上讲它可以是任何东西(即编译器可以说“将NULL指针转换回整数值会导致值0xDEADBEEF ”)。请注意,这意味着即使在 NULL 指针具有值 0 的平台上,编译器也可以在转换时将其转换为任意整数值。然而,实际上,没有编译器会这样做,因为这太疯狂了。

      所以,是的,C 标准允许做很多事情。实际上,您可能使用的任何平台都将 NULL 指针表示为 0,将 NULL 指针转换为整数值将导致 0。查看 here (section 1.14) 以获取不使用 0 作为 NULL 指针的(晦涩)架构的一些异常列表。

      【讨论】:

        【解决方案4】:

        这不适用于 char* 甚至 C,但索引到数组的智能指针类可能会选择将 NULL 表示为 -1,因为 0 是有效的数组索引。

        考虑到 memset( my_new_struct, 0, sizeof my_new_struct ); 的习惯用法,即使是以调试为中心的系统也不太可能打破这种身份。

        【讨论】:

          猜你喜欢
          • 2016-08-25
          • 1970-01-01
          • 1970-01-01
          • 2018-08-16
          • 2021-11-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多