Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
357 views
in Technique[技术] by (71.8m points)

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

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

It doesn't say that a parenthesized null pointer constant is a null pointer constant.

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

Then:

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

The two referenced sections say:

§ 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.

§ 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.

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

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

The bolded sentence says that its type and value are 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*)0 is a null pointer constant. ((void*)0) has the same type and value as (void*)0. var also has the same type and value as (void*)0, but var clearly is not a null pointer constant.

Having said that, I'm 99+% sure that the intent is 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:

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.

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 is 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*)0 and ((void*)0) are address constants. (Well, I think they are.) So what contexts require a null pointer constant and do not accept an address constant? There are only a few.

6.5.9 Equality operators

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:

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

would be a constraint violation.

6.5.16.1 Simple assignment

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 (*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.

7.19 Common definitions <stddef.h>

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

#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 NULL would be a syntax error, expanding to sizeof (void*) followed by an extraneous constant 0.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...