首页 > 解决方案 > c++中值0的特殊状态是什么?

问题描述

这纯粹是一个哲学问题。我假设没有合理的背景可以证明结果是有用的(给定的nullptr)。

根据这个 - https://en.cppreference.com/w/cpp/language/integer_literal,整数文字的类型是int, long int, long long int, unsigned int,unsigned long intunsigned 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));
}

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


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

标签: c++literalsnull-pointer

解决方案


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

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

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

特别是允许的

标准说(最新草案):

[conv.ptr] 空指针常量是一个整数文字 ([lex.icon]),其值为 0 或 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);

自 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));

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


推荐阅读