c++中值0的特殊状态是什么?

Ben*_*y K 3 c++ literals null-pointer

这纯粹是一个哲学问题。我认为没有合理的上下文可以证明结果是有用的(给定nullptr)。

根据这个 - https://en.cppreference.com/w/cpp/language/integer_literal,整数文字的类型是int, long int, long long int, unsigned int, unsigned long intor unsigned long long int,如果文字的值没有,则可能有特定于实现的例外适合以上任何一种。这些类型都不能转换为void *,除非文字的值为 0。

不同的编译器对此有不同的处理方式。例如,考虑以下转换:

void g(void * p){}

void f(){
    int i = 0;
    void * p;
    // p = i; // Fails. Also for other integral types.

    p = 0; // Works. Also for 00, 0x0 and 0b0. Also when adding `u` and `l` suffixes.
    g(0); // Also works.    
    // g(1); // Fails.  

    // Amazingly, even this seems to work with gcc, icc and msvc, but not with clang:
    void * x = static_cast<int>(0);
    // These works for icc and msvc, but fails with gcc and clang
    p = static_cast<int>(0);
    g(static_cast<int>(0));
}
Run Code Online (Sandbox Code Playgroud)

使编译器能够执行这些int->void *转换的“幕后”会发生什么?


编辑:具体来说,问题是标准对此有何看法?

eer*_*ika 6

问题是,为什么根据标准允许这样做

因为需要有一种方式来表达空指针。C 语言的设计者选择 0 为空。C++ 的设计者选择与 C 兼容,因此 0 是空指针常量。

后来在 C++11 中,nullptr作为新关键字引入。不能替换整型空指针常量,因为那样会破坏向后兼容性,因此这些不同的空指针表示方式共存。如果您不需要支持 C++11 之前的系统,则没有理由使用 0 作为空指针。

尤其是允许的内容

标准说(最新草案):

[conv.ptr] 空指针常量是具有零值的整数文字 ([lex.icon]) 或类型为 std?::?nullptr_t 的纯右值。空指针常量可以转换为指针类型;结果是该类型([basic.compound])的空指针值,并且与对象指针或函数指针类型的所有其他值区分开来。这种转换称为空指针转换。相同类型的两个空指针值比较相等。将空指针常量转换为指向 cv 限定类型的指针是一次转换,而不是指针转换后跟限定转换 ([conv.qual]) 的序列。整数类型的空指针常量可以转换为 std?::?nullptr_t 类型的纯右值。[ 注意:生成的纯右值不是空指针值。— 尾注 ]


使编译器能够执行这些 int->void * 转换的“幕后”会发生什么?

编译器解析源。语法说 0 是文字。编译器将 is 视为文字 0,因此可以按照标准将其转换为任何指针类型。


// Amazingly, even this seems to work with gcc, icc and msvc, but not with clang:
void * x = static_cast<int>(0);
Run Code Online (Sandbox Code Playgroud)

这是自 C++11 以来格式错误的。当一个格式错误的程序编译时,通常是因为

  1. 它是语言扩展或
  2. 这是一个编译器错误或
  3. 它在旧版本的语言中格式良好,编译器的目标是

在这种情况下,它可能是一种语言扩展。

// These works for icc and msvc, but fails with gcc and clang
p = static_cast<int>(0);
g(static_cast<int>(0));
Run Code Online (Sandbox Code Playgroud)

自 C++11 以来,这些也是格式错误的。我对 icc 和 msvc 了解不够,无法告诉您这些情况是否是故意的。我建议检查他们的文档。

  • @BennyK 因为 `nullptr` 在 C++11 之前不存在,并且因为 `NULL` 是一个宏,所以你仍然需要一个“null”指针的值,而 0 是一个明显的选择,并且已经在 C 中使用。 (2认同)
  • @BennyK你忘了在你原来的帖子中写下这个问题。 (2认同)