Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 890
user4164058 Avatar asked Oct 21 '14 00:10

user4164058


People also ask

Is void *) 0 the same as null?

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

What does the void *) 0 represent?

JavaScript void 0 means returning undefined (void) as a primitive value. You might come across the term “JavaScript:void(0)” while going through HTML documents. It is used to prevent any side effects caused while inserting an expression in a web page.

Is void null pointer?

The null pointer is basically used in a program to assign the value 0 to a pointer variable of any data type. The void pointer, on the other hand, has no value assigned to it and we use it to store the addresses of other variables in the program- irrespective of their data types.

Is int *) 0 is same as null?

In most cases, these will behave the same. No NULL is usually defined as (void *) 0 it will compare equal to zero but has another type. But '\0' has type int and is equal to 0 — just more typing for exactly the same value. In C++ '\0' has type char but in C it has type int.


1 Answers

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.

like image 193
Keith Thompson Avatar answered Sep 22 '22 04:09

Keith Thompson