What is the type of 1 ? 0L : (long long *)0

S

Spiros Bousbouras

As far as I can tell the expression
1 ? 0L : (long long *)0 violates the constraint
of p. 3 of 6.5.15 but two different compilers are
happy with it so I'm obviously missing something.
What ?
 
S

Spiros Bousbouras

Spiros said:
As far as I can tell the expression
1 ? 0L : (long long *)0 violates the constraint
of p. 3 of 6.5.15 but two different compilers are
happy with it so I'm obviously missing something.
What ?

[#3] One of the following shall hold for the second and
third operands:

-- one operand is a pointer and the other is a null
pointer constant;

The type and value of your whole exprssion is: ((long long *)0)

Is 0L not an arithmetic constant expression ? If yes then
it should have arithmetic type not pointer type.
 
B

Boon

Spiros said:
pete said:
Spiros said:
As far as I can tell the expression
1 ? 0L : (long long *)0 violates the constraint
of p. 3 of 6.5.15 but two different compilers are
happy with it so I'm obviously missing something.
What ?
[#3] One of the following shall hold for the second and
third operands:

-- one operand is a pointer and the other is a null
pointer constant;

The type and value of your whole exprssion is: ((long long *)0)

Is 0L not an arithmetic constant expression ? If yes then
it should have arithmetic type not pointer type.

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

AFAIU, 0L is (also) a null pointer constant.

Even (1-1) seems to be a null pointer constant?
 
J

jameskuyper

Spiros said:
Spiros said:
As far as I can tell the expression
1 ? 0L : (long long *)0 violates the constraint
of p. 3 of 6.5.15 but two different compilers are
happy with it so I'm obviously missing something.
What ?

[#3] One of the following shall hold for the second and
third operands:

-- one operand is a pointer and the other is a null
pointer constant;

The type and value of your whole exprssion is: ((long long *)0)

Is 0L not an arithmetic constant expression ? If yes then
it should have arithmetic type not pointer type.

The fact that 0L is an arithmetic constant expression does not
conflict with the fact that it is also an integer constant expression
with a value of 0. As such, it qualifies as a null pointer constant.
Because it is a null pointer constant it can also be used in many
contexts where an expression of a pointer type would otherwise be
required.

The type of this expression is determined by 6.5.15p6: "If both the
second and third operands are pointers or one is a null pointer
constant and the other is a pointer, the result type is a pointer to a
type qualified with all the type qualifiers of the types pointed-to by
both operands."
 
J

jameskuyper

Boon wrote:
....
An integral constant expression with the value 0, or such an expression
cast to type (void *) is called a null pointer constant.

AFAIU, 0L is (also) a null pointer constant.

Even (1-1) seems to be a null pointer constant?

Correct.
 
S

Spiros Bousbouras

Spiros said:
Spiros Bousbouras wrote:
As far as I can tell the expression
1 ? 0L : (long long *)0 violates the constraint
of p. 3 of 6.5.15 but two different compilers are
happy with it so I'm obviously missing something.
What ?
[#3] One of the following shall hold for the second and
third operands:
-- one operand is a pointer and the other is a null
pointer constant;
The type and value of your whole exprssion is: ((long long *)0)
Is 0L not an arithmetic constant expression ? If yes then
it should have arithmetic type not pointer type.

The fact that 0L is an arithmetic constant expression does not
conflict with the fact that it is also an integer constant expression
with a value of 0. As such, it qualifies as a null pointer constant.

So, although 0L has type long it is also a null pointer constant, yes?
To give another example 0 , 0L , 0u , 0llu are all arithmetic types
but they are also null pointer constants, yes? Is it ever possible for
a null pointer constant to have pointer type?
 
S

Spiros Bousbouras

Is it ever possible for
a null pointer constant to have pointer type?

(void *) expr
where expr is an integer constant expression is the only
possibility I think.
 
K

Keith Thompson

Spiros Bousbouras said:
So, although 0L has type long it is also a null pointer constant, yes?
To give another example 0 , 0L , 0u , 0llu are all arithmetic types
but they are also null pointer constants, yes? Is it ever possible for
a null pointer constant to have pointer type?

Don't get hung up on the name "null pointer constant". As Voltaire
famously said, the Holy Roman Empire was neither holy, nor Roman, nor
an empire; a null pointer constant is at least a constant, even though
it's not necessarily either a null pointer or a pointer. A null
pointer constant is defined by the standard's definition of the term:

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.

Only the first sentence is the definition of the term, so a literal 0
(or 0ULL, or '\0', or ('-'-'-') is a null pointer constant regardless
of the context in which it appears. The second sentence explains what
null pointer constants are good for: converting one to a pointer type
yields a null pointer.

The most important distinction to remember here, IMHO is that a "null
pointer constant" is a construct in C source code, whereas a "null
pointer" is a value that can occur only during program execution.

To answer your question, yes, (void*)0 is a null pointer constant.

Warning: extreme nit-picking follows.

If we take the wording of the standard painfully literally, (void*)0
is by definition a null pointer constant, but ((void*)0) is not. C99
6.5.1p5 defines the attributes of an unparenthesized expression that
are inherited by the corresponding parenthesized expression, namely
its type, its value, whether it's an lvalue, where it's a function
designator, and whether it's a void expression. This list doesn't
include whether it's a null pointer constant. So, strictly speaking,
((void*)0) isn't a null pointer constant. The macro NULL must expand
to a null pointer constant, but it can't expand to (void*)0 because
of 7.1.2p5:

Any definition of an object-like macro described in this clause
shall expand to code that is fully protected by parentheses where
necessary, so that it groups in an arbitrary expression as if it
were a single identifier.

(Note that both 0 and (0) are both null pointer constants, since both
are integer constant expressions.)

But most or all implementations rightly ignore this and treat
((void*)0) as a null pointer constant anyway, which was certainly the
intent. The solution is to clean up the wording of 6.5.1p5.

I was going to argue that (void*)0 is a null pointer constant but
doesn't necessarily yield a null pointer value when evaluated, but
fortunately that's not the case. (void*)0 is a null pointer constant,
which yields a null pointer when converted to a pointer type. If the
NPC itself is not converted (because it's already of type void*), the
standard doesn't actually say that it yields a null pointer. But
we're saved by the fact that 0 is also a null pointer constant, so
(void*)0, in addition to being a null pointer constant itself, is also
a null pointer constant converted to a pointer type.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,444
Messages
2,571,709
Members
48,796
Latest member
Greg L.
Top