C语言 ((void*)0) 是空指针常量吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26477209/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 11:29:46  来源:igfitidea点击:

Is ((void*)0) a null pointer constant?

clanguage-lawyer

提问by user4164058

I'm reading this blog postand under the section Null pointer constants and parenthesized expressionsthe author references § 6.3.2.3 and § 6.5.1 from the ISO C standard and says:

我正在阅读这篇博客文章,在Null 指针常量和括号表达式部分下,作者引用了 ISO C 标准中的 § 6.3.2.3 和 § 6.5.1 并说:

It doesn'tsay that a parenthesized null pointer constant is a null pointer constant.

Which implies, strictly speaking, that (void*)0is a null pointer constant, but ((void*)0)is not.

并没有说带括号的空指针常量是空指针常量。

这意味着,严格来说,这(void*)0是一个空指针常量,但((void*)0)不是。

Then:

然后:

I'm sure that most C implementations do treat a parenthesized null pointer constant as a null pointer constant, and define NULLeither as 0, ((void*)0), or in some other manner.

我敢肯定,大多数C实现根本治疗括号中的空指针常数作为空指针常数,并定义NULL无论是作为0((void*)0)或以其他的方式。

The two referenced sections say:

两个参考部分说:

§ 6.3.2.3

§ 6.3.2.3

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.

值为 0 的整数常量表达式,或转换为 void * 类型的此类表达式,称为空指针常量。

§ 6.5.1

§ 6.5.1

A parenthesized expression is a primary expression. Its type and value are identical to those of the unparenthesized expression.It is an lvalue, a function designator, or a void expression if the unparenthesized expression is, respectively, an lvalue, a function designator, or a void expression.

带括号的表达式是主要表达式。它的类型和值与未加括号的表达式的类型和值相同。如果未加括号的表达式分别是左值、函数指示符或 void 表达式,则它是左值、函数指示符或 void 表达式。

Doesn't the bolded sentence contradict the author's claim that ((void*)0)is not a null pointer constant?

粗体的句子是否与作者声称((void*)0)的不是空指针常量的说法相矛盾?

采纳答案by Keith Thompson

Doesn't the bolded sentence contradict the author's claim that ((void*)0)is not a null pointer constant?

粗体的句子是否与作者声称((void*)0)的不是空指针常量的说法相矛盾?

No, it doesn't. (I confess to being a bit biased, since the referenced blog is mine.)

不,它没有。(我承认有点偏见,因为引用的博客是我的。)

The bolded sentence says that its typeand valueare identical to those of the unparenthesized expression. That's not enough to imply that it's a null pointer constant.

加粗的句子表示它的类型与未加括号的表达式的类型相同。这不足以暗示它是一个空指针常量。

Consider:

考虑:

void *var = 0;

(void*)0is a null pointer constant. ((void*)0)has the same type and value as (void*)0. varalsohas the same type and value as (void*)0, but varclearly is not a null pointer constant.

(void*)0是一个空指针常量。((void*)0)与 具有相同的类型和值(void*)0var具有与 相同的类型和值(void*)0,但var显然不是空指针常量。

Having said that, I'm 99+% sure that the intentis that ((void*)0)is a null pointer constant, and more generally that any parenthesized null pointer constant is a null pointer constant. The authors of the standard merely neglected to say so. And since the description of parenthesized expressions in 6.5.1p5 specifically enumerates several other characteristics that are inherited by parenthesized expressions:

话虽如此,我 99+% 确定意图((void*)0)空指针常量,更一般地说,任何带括号的空指针常量都是空指针常量。该标准的作者只是忽略了这样说。并且由于6.5.1p5中括号表达式的描述专门列举了括号表达式继承的其他几个特性:

A parenthesized expression is a primary expression. Its type and value are identical to those of the unparenthesized expression. It is an lvalue, a function designator, or a void expression if the unparenthesized expression is, respectively, an lvalue, a function designator, or a void expression.

带括号的表达式是主要表达式。它的类型和值与未加括号的表达式的类型和值相同。如果未加括号的表达式分别是左值、函数指示符或 void 表达式,则它是左值、函数指示符或 void 表达式。

the omission is troubling (but only mildly so).

遗漏令人不安(但只是轻微的)。

But let's assume, for the sake of argument, that ((void*)0)is not a null pointer constant. What difference does it make?

但是为了论证,让我们假设这((void*)0)不是空指针常量。它有什么区别?

(void*)0is a null pointer constant, whose value is a null pointer of type void*, so by the semantics of parenthesized expressions ((void*)0)also has a value that is a null pointer of type void*. Both (void*)0and ((void*)0)are address constants. (Well, I thinkthey are.) So what contexts require a null pointer constantand do not accept an address constant? There are only a few.

(void*)0是一个空指针常量,其值为 type 的空指针void*,因此根据括号表达式的语义,((void*)0)也有一个值为 type 的空指针void*。这两个(void*)0((void*)0)地址常量。(好吧,我认为它们是。)那么什么上下文需要空指针常量而不接受地址常量呢?只有几个。

6.5.9 Equality operators

6.5.9 等式运算符

An expression of function pointer type may be compared for equality to a null pointer constant. (An object pointer may be compared to an expression of type void*, but a function pointer may not, unless it's a null pointer constant.) So this:

可以将函数指针类型的表达式与空指针常量的相等性进行比较。(对象指针可以与 type 的表达式进行比较void*,但函数指针不能,除非它是空指针常量。)所以这个:

void func(void);
if (func == ((void*)0)) { /* ... */ }

would be a constraint violation.

将违反约束。

6.5.16.1 Simple assignment

6.5.16.1 简单赋值

In an assignment, a null pointer constant may be assigned to an object of pointer-to-function type, and will be implicitly converted. An expression of type void*that's not a null pointer constant may not be assigned to a function pointer. The same constraints apply to argument passing and initialization. So this:

在赋值中,空指针常量可能会被赋值给函数指针类型的对象,并且会被隐式转换。void*不能将非空指针常量类型的表达式分配给函数指针。相同的约束适用于参数传递和初始化。所以这:

void (*fp)(void) = ((void*)0);

would be a constraint violation if ((void*)0)were not a null pointer constant. Thanks to commenter hvd for finding this.

如果((void*)0)不是空指针常量,则会违反约束。感谢评论者 hvd 找到了这个。

7.19 Common definitions <stddef.h>

7.19 通用定义 <stddef.h>

The macro NULLexpands to "an implementation-defined null pointer constant". If ((void*)0)is not a null pointer constant, then this:

NULL扩展为“一个实现定义的空指针常量”。如果((void*)0)不是空指针常量,则:

#define NULL ((void*)0)

would be invalid. This would be a restriction imposed on the implementation, not on programmers. Note that this:

将无效。这将是对实现的限制,而不是对程序员的限制。请注意:

#define NULL (void*)0

is definitely invalid, since macro definitions in standard headers must be fully protected by parentheses where necessary (7.1.2p5). Without the parentheses, the valid expression sizeof NULLwould be a syntax error, expanding to sizeof (void*)followed by an extraneous constant 0.

绝对无效,因为标准头文件中的宏定义必须在必要时由括号完全保护(7.1.2p5)。如果没有括号,有效的表达式sizeof NULL将是一个语法错误,扩展为sizeof (void*)后跟一个无关的常量0

回答by Ben Voigt

It is a parenthesized expression which contains a null pointer constant, so it indisputably is a null pointer value. Using it as an rvalue has exactly the same effect as using the "compliant" version as an r-value.

它是一个带括号的表达式,其中包含一个空指针常量,因此它无可争议地是一个空指针值。将其用作右值与将“兼容”版本用作右值具有完全相同的效果。

If there were some syntactic rules that could onlyaccept a null pointer constant, it would not qualify. But I'm not aware of any (though I'm less expert on C).

如果有一些语法规则只能接受一个空指针常量,它就没有资格。但我不知道任何(尽管我不太熟悉 C)。

And while neither one is a constant(referring to the formal grammar production), both can appear in a constant expression in an initializer, because both null pointer constants and address constants are allowed, and a constant null pointer value is explicitly included in the category of address constant.

虽然两者都不是常量(指形式语法产生式),但两者都可以出现在初始化器中的常量表达式中,因为空指针常量和地址常量都是允许的,并且常量空指针值明确包含在类别中的地址不变

Pointer comparisons also specifically mention null pointer constants... but here pointer values are also accepted, and all null pointer values are treated equally. Same for the ternary and assignment operators.

指针比较还特别提到了空指针常量……但这里也接受指针值,并且所有空指针值都被同等对待。三元运算符和赋值运算符也是如此。

Please do be aware that these rules are quite different in C++, where both the above expressions are constant null pointer values of type void*, but not universal null pointer constants. Null pointer constants in C++ are integral constant expressionswhich evaluate to zero. And void*doesn't implicitly convert to other pointer types.

请注意,这些规则在 C++ 中完全不同,其中上述两个表达式都是类型为 的常量空指针值void*,而不是通用空指针常量。C++ 中的空指针常量是计算为零的整数常量表达式。并且void*不会隐式转换为其他指针类型。

回答by Rupali Gaikwad

Try printing below line in your C code:

尝试在您的 C 代码中打印以下行:

printf("%p",(void*)0);

printf("%p",(void*)0);

You will get the output as:

您将获得如下输出:

(nil)

(零)