问题描述
这可以被看作是一个扩展(我只是很感兴趣,C,但加入C ++完成扩展)
This could be thought of as an extension to this question (I'm interested in C only, but adding C++ to complete the extension)
在6.3.2.3.3的C11标准说:
The C11 standard at 6.3.2.3.3 says:
值为0,或者这样一个前pression投整型常量前pression键入无效*
,被称为空指针常量。
什么我采取这一个人是 0
和(无效*)0
重新present的空指针,其整数值实际上可能不是0,但不包括0强制转换为任何其他类型。
What my take on this personally is that 0
and (void *)0
represent the null pointer, whose integer value may not actually be 0, but that doesn't cover 0 cast to any other type.
不过,标准接着说:
如果空指针常数转换为指针类型,所得到的指针,称为空指针的,...
覆盖(INT *)0
为空指针,因为转换是一种的显式转换是在转换方法列出的(C11,6.3)
which covers (int *)0
as null pointer since cast is an explicit conversion (C11, 6.3) which is listed under conversion methods.
不过,还是让我纳闷的是下面这句
However, what still makes me wonder is the following phrase
...或者这样一个前pression投键入无效*
...
通过上面的语义,这句话似乎完全无用。现在的问题是,是这句话完全没用?如果不是,它有什么意义呢?因此,为(INT *)0
空指针或没有?
With the above semantics, this phrase seems completely useless. The question is, is this phrase completely useless? If not, what implications does it have? Consequently, is (int *)0
the null pointer or not?
这可以帮助讨论的另一个问题是,以下。为(久长)123
认为123转换为长长
或123型长长
。换句话说,有没有任何转换(久长)123
?如果没有,那么上面的第二个报价的不的盖(INT *)0
作为一个空指针。
Another question that can help the discussion is the following. Is (long long)123
considered "123 converted to long long
", or "123 with type long long
". In other words, is there any conversion in (long long)123
? If there is none, then the second quote above doesn't cover (int *)0
as a null pointer.
推荐答案
简短的回答:
在C和C ++,(INT *)0
是一个常量前pression它的值是一个空指针。它不是,但是,一个的空指针常量的。恒恩$ P $之间的唯一可见差异pssion-的价值 - 是 - 一个空指针和一个空指针常数,即我所知道的是,一个空指针常数可以被分配到任何指针类型的左值,而是一个恒定的前pression-的价值 - 是 - 一个空指针都有特定的指针类型,只能分配给左值具有兼容类型。在C,而不是C ++,(无效*)0
也是一个空指针常数;这是一个特例无效*
与一般的C-但并非C ++规则无效*
是一致的分配与任何其他指针到对象的类型兼容。
In both C and C++, (int *)0
is a constant expression whose value is a null pointer. It is not, however, a null pointer constant. The only observable difference between a constant-expression-whose-value-is-a-null-pointer and a null-pointer-constant, that I know of, is that a null-pointer-constant can be assigned to an lvalue of any pointer type, but a constant-expression-whose-value-is-a-null-pointer has a specific pointer type and can only be assigned to an lvalue with a compatible type. In C, but not C++, (void *)0
is also a null pointer constant; this is a special case for void *
consistent with the general C-but-not-C++ rule that void *
is assignment compatible with any other pointer-to-object type.
例如:
long *a = 0; // ok, 0 is a null pointer constant
long *b = (long *)0; // ok, (long *)0 is a null pointer with appropriate type
long *c = (void *)0; // ok in C, invalid conversion in C++
long *d = (int *)0; // invalid conversion in both C and C++
和这里的情况下空指针常量(无效*)0
和恒定-EX pression,其价值-is-a的之间的区别-null指针类型无效*
是可见的,即使是在C:
And here's a case where the difference between the null pointer constant (void *)0
and a constant-expression-whose-value-is-a-null-pointer with type void *
is visible, even in C:
typedef void (*fp)(void); // any pointer-to-function type will show this effect
fp a = 0; // ok, null pointer constant
fp b = (void *)0; // ok in C, invalid conversion in C++
fp c = (void *)(void *)0; // invalid conversion in both C and C++
此外,这是毫无意义的今天,但既然你提出来的:无论是什么的比特重的presentation长*
ş空指针是,所有的这些断言的行为的意见所示:
Also, it's moot nowadays, but since you brought it up: No matter what the bit representation of long *
's null pointer is, all of these assertions behave as indicated by the comments:
// 'x' is initialized to a null pointer
long *x = 0;
// 'y' is initialized to all-bits-zero, which may or may not be the
// representation of a null pointer; moreover, it might be a "trap
// representation", UB even to access
long *y;
memset(&y, 0, sizeof y);
assert (x == 0); // must succeed
assert (x == (long *)0); // must succeed
assert (x == (void *)0); // must succeed in C, unspecified in C++
assert (x == (int *)0); // must succeed in C, unspecified in C++
assert (memcmp(&x, &y, sizeof y) == 0); // unspecified
assert (y == 0); // UNDEFINED BEHAVIOR: y may be a trap representation
assert (y == x); // UNDEFINED BEHAVIOR: y may be a trap representation
未指定比较不招惹不确定的行为,但该标准并没有说他们是否评估真或假,并且不需要执行记录哪两个是,甚至挑一,坚持以它。这将是非常有效的对上述 memcmp
来替代返回0和1之间,如果你叫了很多次。
"Unspecified" comparisons do not provoke undefined behavior, but the standard doesn't say whether they evaluate true or false, and the implementation is not required to document which of the two it is, or even to pick one and stick to it. It would be perfectly valid for the above memcmp
to alternate between returning 0 and 1 if you called it many times.
龙答案与标准的报价:
要了解什么是的空指针常量的是,你首先要了解什么是的整型常量前pression 的是,这是pretty毛茸茸 - - 一个全面的了解,需要您阅读部分6.5,并详细C99 6.6。这是我的总结:
To understand what a null pointer constant is, you first have to understand what an integer constant expression is, and that's pretty hairy -- a complete understanding requires you to read sections 6.5 and 6.6 of C99 in detail. This is my summary:
-
一个的恒前pression 的是任何C EX pression,编译器可以评估一个常数不知道任何对象的值(
常量
或以其他方式;但是,枚举
值是公平的游戏),并具有无副作用。 (这是大约25页standardese的急剧简化,可能不准确。)
A constant expression is any C expression which the compiler can evaluate to a constant without knowing the value of any object (
const
or otherwise; however,enum
values are fair game), and which has no side effects. (This is a drastic simplification of roughly 25 pages of standardese and may not be exact.)
的整型常量前pressions 的恒定前pressions的受限子集,在单款方便的定义,C99 6.6p6其注脚:
Integer constant expressions are a restricted subset of constant expressions, conveniently defined in a single paragraph, C99 6.6p6 and its footnote:
这是整型常量前pression 应具有整数类型,并应只能有一个是整型常量,枚举常量,字符常量,操作数的sizeof
前pressions,其结果是整型常量和浮动常数,强制转换的直接操作数。铸造运营商在一个整型常量前pression只能转换算术类型为整数类型,除了作为一个操作数的一部分的sizeof
运营商。
整型常量前pression用于指定的结构的位字段成员的大小,枚举常量的值,数组的大小,或案件常量的值。适用于所用整型常量前pressions进一步约束[#如果
]在6.10.1讨论。
An integer constant expression is used to specify the size of a bit-field member of a structure, the value of an enumeration constant, the size of an array, or the value of a case constant. Further constraints that apply to the integer constant expressions used in [#if
] are discussed in 6.10.1.
有关本次讨论的目的,重要的位
For purpose of this discussion, the important bit is
转换操作符......应只转换算术类型为整数类型
这意味着(INT *)0
是的不的一个整数的不断前pression,虽然这是一个不断前pression。
which means that (int *)0
is not an integer constant expression, although it is a constant expression.
在C ++ 98的定义似乎更或相当少,模C ++的功能和偏离C.例如,字符和布尔类型从整数类型在C ++中的强分离意味着C ++标准说的是积分的不断前pressions,而不是整数的不断前pressions,然后有时需要不只是一个整型常量前pression,而是一个整型常量前pression的整型的,不包括字符
, wchar_t的
,和布尔
(可能还有符号字符
和 unsigned char型
?这不是很清楚,我从文本)。
The C++98 definition appears to be more or less equivalent, modulo C++ features and deviations from C. For instance, the stronger separation of character and boolean types from integer types in C++ means that the C++ standard speaks of "integral constant expressions" rather than "integer constant expressions", and then sometimes requires not just an integral constant expression, but an integral constant expression of integer type, excluding char
, wchar_t
, and bool
(and maybe also signed char
and unsigned char
? it's not clear to me from the text).
现在,的C99定义的空指针常量的是这个问题的意义所在,所以我会再说一遍:6.3.2.3p3说:
Now, the C99 definition of null pointer constant is what this question is all about, so I'll repeat it: 6.3.2.3p3 says
值为0,或者这样的前pression投整型常量前pression键入
无效*
,被称为的空指针常量的。如果空指针常数被转换为一个
指针类型,所得到的指针,称为空指针的,是保证比较不等的指针的任何对象或功能。
Standardese是非常,非常的文字。这两句话的意思是完全一样的东西:
Standardese is very, very literal. Those two sentences mean exactly the same thing as:
值为0的整型常量前pression叫做的空指针常量的。结果
整型常量前pression值为0,转换为键入无效*
是同时 空指针常量。结果
当任何空指针常量被转换为指针类型,所产生的指针被称为的空指针的并保证比较不等...
(斜体字 - 。长期黑体的定义 - 我的重点),那么这意味着什么,在C,(长*)0
和 (长*)(无效*)0
正在编写完全一样的东西,即空指针类型的两种方法长*
。
(Italics - definition of term. Boldface - my emphasis.) So what that means is, in C, (long *)0
and (long *)(void *)0
are two ways of writing exactly the same thing, namely the null pointer with type long *
.
C ++是不同的。等效文字是C ++ 98 4.10 [conv.ptr]:
C++ is different. The equivalent text is C++98 4.10 [conv.ptr]:
A 空指针常量的是一个整型常量前pression计算结果为零整数类型(5.19)右值。
这就是全部。 整数类型的积分常数前pression右值,是非常接近一回事C99的整型常量前pression,但也有在C出线的几件事情,但不是C ++:例如,在C该字符文字'\\ X00'
是一个整型常量前pression,因此空指针常量,但在C ++中,它是的不的整数类型的整型常量前pression,所以它不是一个空指针常量无论是。
That's all. "Integral constant expression rvalue of integer type" is very nearly the same thing as C99's "integer constant expression", but there are a few things that qualify in C but not C++: for instance, in C the character literal '\x00'
is an integer constant expression, and therefore a null pointer constant, but in C++ it is not an integral constant expression of integer type, so it is not a null pointer constant either.
更重要的是,虽然C ++不具备或者这样一个前pression投地无效*
的条款。这意味着,((无效*)0)
是不会一个空指针常数C ++。它仍然是一个的空指针的,但它不是分配与任何其他指针类型兼容。这是C ++的普遍挑剔的类型系统是一致的。
More to the point, though, C++ doesn't have the "or such an expression cast to void *
" clause. That means that ((void *)0)
is not a null pointer constant in C++. It is still a null pointer, but it is not assignment compatible with any other pointer type. This is consistent with C++'s generally pickier type system.
C ++ 11(但不,据我所知,C11)修订的空指针的理念,加入了特殊类型它们( nullptr_t
)和一个新的关键词将计算得到一个空指针常数( nullptr
)。我不完全理解的变化,我不会试图解释他们,但我pretty确保裸 0
仍然是一个有效的空指针在不断C ++ 11。
C++11 (but not, AFAIK, C11) revised the concept of "null pointer", adding a special type for them (nullptr_t
) and a new keyword which evaluates to a null pointer constant (nullptr
). I do not fully understand the changes and am not going to try to explain them, but I am pretty sure that a bare 0
is still a valid null pointer constant in C++11.
这篇关于是为(int *)0空指针?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!