【问题标题】:Does Standard define null pointer constant to have all bits set to zero?标准是否定义空指针常量以将所有位设置为零?
【发布时间】:2015-02-27 03:28:51
【问题描述】:

(我引用的是 ISO/IEC 9899:201x)

这里我们看到,整数常量表达式有一个整数类型:

6.6 常量表达式

6。 整数常量表达式应该是整数类型并且应该只有操作数 即整数常量、枚举常量、字符常量、sizeof 结果是整数常量、_Alignof 表达式和浮点数的表达式 作为强制转换的直接操作数的常量。在整数常量中转换运算符 表达式只能将算术类型转换为整数类型,除非作为 sizeof 或 _Alignof 运算符的操作数。

那么这适用于任何整数类型:

6.2.6.2 整数类型

5。 未指定任何填充位的值。有效(非陷阱)对象表示 符号位为零的有符号整数类型是 对应的无符号类型,并且应该代表相同的值。 对于任何整数类型, 所有位为零的对象表示应是值的表示 该类型为零。

然后我们看到空指针常量是使用值为0的整数常量表达式定义的。

6.3.2.3 指针

3。 值为 0 的整数常量表达式,或这种类型的表达式 void*, 称为空指针常量。 如果将空指针常量转换为 指针类型,结果指针,称为空指针,保证比较不相等 指向任何对象或函数的指针。

因此,空指针常量必须将其所有位设置为零。

但是网上和 StackOverflow 上有很多答案说这不是真的。

鉴于引用的部分,我很难相信他们。

(请参考最新标准回答)

【问题讨论】:

  • 首先,6.2.6.2/5 说“所有位为零”结果为 0,而不是 0 必须是所有位为零。此外,将整数转换为指针的结果是实现定义的(6.3.2.3/5),因此将 0 转换为 void * 类型的结果不一定都是零位。
  • @T.C.这听起来很矛盾。如果所有位为零表示值0,则值0 必须所有位为零。
  • @2501 不,因为值和位模式之间不一定存在一对一的相关性。
  • @2501:您可以将 24 位 int 存储在 32 位中,并忽略 8 个填充位。包括填充位零在内的所有位都是 0。但 0 可能有一些未设置的填充位。
  • @2501:必须有一个所有位为零的值为零,但不能保证只有一个零——可能还有其他位模式也为零,并使用 @ 987654324@ 文字可能会为您提供其他模式之一,而不是全 0 位模式。真正的问题是全零位表示是否是空指针,标准并没有真正解决这个问题。

标签: c standards language-lawyer


【解决方案1】:

C 标准的一个主要限制是,由于作者希望避免禁止编译器以任何地方的任何生产代码可能依赖的任何方式运行,它未能指定程序员需要知道的许多事情。因此,通常需要对标准未指定但与常见编译器的行为相匹配的事物进行假设。构成空指针的所有字节都为零这一事实就是这样一种假设。

除了每个数据类型的每个可能的值(包括指针)都可以表示为char值的序列这一事实之外,C 标准中没有任何内容指定任何指针的位级表示( *)。尽管如此,在几乎所有通用平台上,将与结构关联的所有字节清零相当于将所有成员设置为其类型的静态默认值(指针的默认值为 null)。此外,使用calloc 接收归零的RAM 块用于结构集合的代码通常比使用malloc 的代码要快得多,然后必须手动清除每个结构的每个成员,或者使用calloc,但仍手动清除每个结构的每个非整数成员。

因此,我建议在许多情况下,针对 C 的方言编写代码是完全合理的,其中空指针存储为全字节为零,并且作为文档要求它不适用于以下方言事实并非如此。也许有一天 ISO 会提供一种标准方法,通过这种方法可以将这些要求以机器可读的形式记录下来(这样每个编译器都必须遵守程序声明的要求或拒绝编译),但据我所知还没有存在。

(*) 据我了解,关于编译器是否需要再遵守该假设存在一些问题。例如,考虑:

int funcomp(int **pp, int **qq)
{
    int *p,*q;
    p = (int*)malloc(1234);
    *pp = p;
    free(p);
    q = (int*)malloc(1234);
    *qq = q;
    *q = 1234;
    if (!memcmp(pp, qq, sizeof p))
      return *p;
    return 0;
 }

free(p) 之后,任何访问*p 的尝试都将是未定义行为。尽管q 很可能会收到与p 完全相同的位模式,但标准中的任何内容都不会要求p 必须被视为q 的有效别名,即使在这种情况下也是如此。另一方面,说两个相同类型的变量可以保存完全相同的位而它们的内容却不相等似乎也很奇怪。因此,虽然很自然地允许函数返回 0 以及不按位比较相等的 *pp*qq 的值,或者返回 1234 以及 *pp*qq 的值确实比较按位相等,如果malloc 碰巧产生按位等效值,标准似乎允许函数任意运行。

【讨论】:

    【解决方案2】:

    不,NULL 不必全部为零。

    N1570 6.3.2.3 指针第 3 段:

    值为 0 的整数常量表达式,或这种类型的表达式 void *,称为空指针常量。 66) 如果一个空指针常量被转换为一个 指针类型,得到的指针,称为空指针,保证比较不相等 指向任何对象或函数的指针。

    看我上面的重点:整数0转换的 如有必要,它不必具有相同的位表示。

    页面底部的注释 66 说:

    66) 宏 NULL 在(和其他头文件)中定义为空指针常量;见 7.19。

    这将我们引向该章的一段:

    宏是

    扩展为实现定义的空指针常量

    更重要的是,附件 J.3.12(可移植性问题、实现定义的行为、库函数)说:

    ——宏 NULL 扩展的空指针常量 (7.19)。

    【讨论】:

    • 第一个语句有点令人困惑,因为NULL(空指针constant)必须为0,但空指针不需要.
    • 我听说过这样的例子,其中寄存器映射到小型处理器上,从地址 0 开始。因此,该特定模式将 null 定义为 255 而不是 0,因为他们希望保留能够引用第一个寄存器。
    【解决方案3】:

    询问空指针常量的表示是毫无意义的。

    空指针常量要么具有整数类型,要么具有 void* 类型。不管它是什么,它都是一个。它不是一个对象。值没有表示,只有对象有。我们只能通过获取对象的地址、将其转换为 char* 或 unsigned char* 并查看字节来讨论表示。我们不能用空指针常量来做到这一点。一旦它被分配给一个对象,它就不再是一个空指针常量了。

    【讨论】:

    • 这并不是毫无意义的,例如,如果我使用 calloc() 分配一个 char* 数组(即 char**),那么能够依赖它们被初始化为 null 可能会很有用.正如已经表明的那样,这种方法是不可移植的。
    【解决方案4】:

    标准是否定义空指针常量以将所有位设置为零?

    不,它没有。 C 标准的任何段落都没有强加这样的要求。

    void *p = 0;
    

    例如p 是一个空指针,但标准不要求对象p 必须设置所有位。

    有关信息,c-faq 网站在此处提到了一些具有非零空指针表示的系统:http://c-faq.com/null/machexamp.html

    【讨论】:

    • @Jasen +1 - 那是促销。好点 - 对象中的位实际上发生了变化。另一个例子是int to double Promotion。
    猜你喜欢
    • 1970-01-01
    • 2012-10-26
    • 1970-01-01
    • 2014-01-05
    • 2014-06-10
    • 2017-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多