c++中0值的特殊地位是什么?
What is the special status of the value 0 in c++?
这纯粹是一个哲学问题。我假设没有合理的上下文证明结果是有用的(给定 nullptr
)。
根据这个-https://en.cppreference.com/w/cpp/language/integer_literal,整数文字的类型是int
、long int
、long long int
、unsigned int
、unsigned long int
或 unsigned long long int
,如果文字的值不符合上述任何一项,则可能存在特定于实现的异常。
None 这些类型可转换为 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));
}
发生了什么 "under the hood" 使编译器能够执行这些 int
->void *
转换?
编辑:
具体来说,问题是标准对此有何规定?
The question is, why is this permitted according to the standard
因为需要有一种方法来表达空指针。 C 语言的设计者选择 0 为空。 C++的设计者选择了兼容C,所以0是一个空指针常量。
后来在 C++11 中,nullptr
作为新关键字引入。不可替换整型空指针常量,因为那样会破坏向后兼容性,因此这些表示空的不同方式并存。如果您不需要支持 C++11 之前的系统,则没有理由将 0 用作空指针。
and specifically what is permitted
标准说(最新草案):
[conv.ptr] A null pointer constant is an integer literal ([lex.icon]) with value zero or a prvalue of type std::nullptr_t.
A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type ([basic.compound]) and is distinguishable from every other value of object pointer or function pointer type.
Such a conversion is called a null pointer conversion.
Two null pointer values of the same type shall compare equal.
The conversion of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the sequence of a pointer conversion followed by a qualification conversion ([conv.qual]).
A null pointer constant of integral type can be converted to a prvalue of type std::nullptr_t.
[ Note: The resulting prvalue is not a null pointer value.
— end note
]
What happens "under the hood" that enables compilers to perform these int->void * conversions?
编译器解析源代码。语法说 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 以来,这是格式错误的。当一个格式错误的程序编译时,通常是因为
- 它是一个语言扩展或者
- 这是编译器错误或
- 它在旧版本的语言中格式正确,编译器的目标是
在这种情况下,它可能是语言扩展。
// 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 的了解还不够,无法告诉您这些情况是否是故意的。我建议查看他们的文档。
What happens "under the hood" that enables compilers to perform these int
->void *
conversions?
魔术(如果您愿意,也可以只是专用规则)。字面 0
(以及 0u
、0l
和其他变体)是特殊的。只有当这些确切的标记出现在源代码中时,编译器才会认为到指针的转换是有效的。不是0的值,是token
[conv.ptr] (emphasis mine)
1 A null pointer constant is an integer literal with value
zero or a prvalue of type std::nullptr_t
. A null pointer constant
can be converted to a pointer type; the result is the null pointer
value of that type and is distinguishable from every other value of
object pointer or function pointer type. Such a conversion is called a
null pointer conversion.
一个 "integer literal" 具有如 [lex.icon] 中所述的精确含义。它是可以出现在我们程序源代码中的标记规范。上面引用的段落告诉我们哪些标记具有特殊含义。
我怀疑您看到的行为差异是由于 C 编程语言造成的。根据编译器前端的实现方式,它可能是此错误的来源。在C语言中,任何值为0的整型常量表达式都是空指针常量。
6.3.2.3 Pointers
3 An integer constant expression with the value 0, or such an
expression cast to type void *
, is called a null pointer constant. If
a null pointer constant is converted to a pointer type, the resulting
pointer, called a null pointer, is guaranteed to compare unequal to a
pointer to any object or function.
在 C++ 中也是如此,直到 CWG Issue 903 被解析为我们今天在 C++ 中拥有的规则。
如果某些编译器混合了他们的 C 和 C++ 逻辑,或者没有抓住缺陷报告的解决方案,它会解释您的观察结果。
这纯粹是一个哲学问题。我假设没有合理的上下文证明结果是有用的(给定 nullptr
)。
根据这个-https://en.cppreference.com/w/cpp/language/integer_literal,整数文字的类型是int
、long int
、long long int
、unsigned int
、unsigned long int
或 unsigned long long int
,如果文字的值不符合上述任何一项,则可能存在特定于实现的异常。
None 这些类型可转换为 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));
}
发生了什么 "under the hood" 使编译器能够执行这些 int
->void *
转换?
编辑: 具体来说,问题是标准对此有何规定?
The question is, why is this permitted according to the standard
因为需要有一种方法来表达空指针。 C 语言的设计者选择 0 为空。 C++的设计者选择了兼容C,所以0是一个空指针常量。
后来在 C++11 中,nullptr
作为新关键字引入。不可替换整型空指针常量,因为那样会破坏向后兼容性,因此这些表示空的不同方式并存。如果您不需要支持 C++11 之前的系统,则没有理由将 0 用作空指针。
and specifically what is permitted
标准说(最新草案):
[conv.ptr] A null pointer constant is an integer literal ([lex.icon]) with value zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type ([basic.compound]) and is distinguishable from every other value of object pointer or function pointer type. Such a conversion is called a null pointer conversion. Two null pointer values of the same type shall compare equal. The conversion of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the sequence of a pointer conversion followed by a qualification conversion ([conv.qual]). A null pointer constant of integral type can be converted to a prvalue of type std::nullptr_t. [ Note: The resulting prvalue is not a null pointer value. — end note ]
What happens "under the hood" that enables compilers to perform these int->void * conversions?
编译器解析源代码。语法说 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 以来,这是格式错误的。当一个格式错误的程序编译时,通常是因为
- 它是一个语言扩展或者
- 这是编译器错误或
- 它在旧版本的语言中格式正确,编译器的目标是
在这种情况下,它可能是语言扩展。
// 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 的了解还不够,无法告诉您这些情况是否是故意的。我建议查看他们的文档。
What happens "under the hood" that enables compilers to perform these
int
->void *
conversions?
魔术(如果您愿意,也可以只是专用规则)。字面 0
(以及 0u
、0l
和其他变体)是特殊的。只有当这些确切的标记出现在源代码中时,编译器才会认为到指针的转换是有效的。不是0的值,是token
[conv.ptr] (emphasis mine)
1 A null pointer constant is an integer literal with value zero or a prvalue of type
std::nullptr_t
. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type. Such a conversion is called a null pointer conversion.
一个 "integer literal" 具有如 [lex.icon] 中所述的精确含义。它是可以出现在我们程序源代码中的标记规范。上面引用的段落告诉我们哪些标记具有特殊含义。
我怀疑您看到的行为差异是由于 C 编程语言造成的。根据编译器前端的实现方式,它可能是此错误的来源。在C语言中,任何值为0的整型常量表达式都是空指针常量。
6.3.2.3 Pointers
3 An integer constant expression with the value 0, or such an expression cast to type
void *
, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.
在 C++ 中也是如此,直到 CWG Issue 903 被解析为我们今天在 C++ 中拥有的规则。
如果某些编译器混合了他们的 C 和 C++ 逻辑,或者没有抓住缺陷报告的解决方案,它会解释您的观察结果。