Topic: What is a null pointer constant?


Author: rgetov@hotmail.com (Radoslav Getov)
Date: Fri, 9 Nov 2001 08:15:22 GMT
Raw View
"Al Grant" <tnarga@arm.REVERSE-NAME.com> wrote in message news:<9rrur2$a7i$1@cam-news1.cambridge.arm.com>...

[snip]
>
> I misread the standard.  4.9 says float to int always truncates.
> So static_cast<int>(0.1f) has to be 0.  If that means that an
> expression that looks like an integral constant-expression always
> _is_ constant (even at runtime), then there is no need to make
> the distinction I was trying to make.

I admit it's just a curious example, but the temptation is too great:

    int *a = __LINE__ % 2;

So, is this a legal or not? Well, you guessed: it depends on which
line it is.

Probably even wierder examples exist. I personally think that we need
is a null pointer keyword in order to get rid of 'constant integral
expression evaluating to 0'.

Radoslav Getov

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Al Grant" <tnarga@arm.REVERSE-NAME.com>
Date: Thu, 1 Nov 2001 15:11:03 GMT
Raw View
[5.19] defines constant-expressions and lists where they
are used.  It says that the cases in which expressions are
"considered" as constant-expressions are, generally,
static initializers [3.6.2] and for integer type:

  array bounds
  case
  bit-field lengths
  enum initializers
  static member initializers
  template arguments

That is, whether an expression is "considered" as a
constant-expression depends on the context.  For example,
a pointer expression "considered" as a constant-expression
would need to be an address constant or a null pointer
constant.  [5.19] explicitly says that a pointer expression
is considered a constant-expression *only* for the purpose
of non-local static object initialization, implying that in
other contexts expressions are never constant-expressions.

But [4.10] says that "a null pointer constant is an integral
constant-expression (5.19) rvalue of integer type that
evaluates to zero".  This surely isn't right.  [5.19] defines
the _contexts_ where an expression is considered a
constant-expression, and states the acceptable expressions
in those contexts.  It does _not_ define whether an expression
is a constant-expression, or not, on the basis of its content.
The logical reading of [4.10] and [5.19] together is that
null pointer constants, being constant-expressions, only
occur in static initializers.

Does that mean that there are certain other contexts in which
expressions are constant-expressions for the purposes of being
null pointer constants?  For example: "one side of a relational
operator where the other side is of pointer type"?  Is it
possible to list these contexts exhaustively?

As an example of why this matters, consider whether

  static_cast<int>(0.5f)

is an integral constant-expression.  [4.8] says the value
resulting from this cast is an implementation-defined choice
of 0 or 1.  So an implementation could define that it is 0 when
it is an integral constant-expression ([5.19] tells it exactly
when this is the case) and a non-constant, rounding-mode choice
of 0 or 1 otherwise.  But as we now know, [5.19] doesn't define
all the contexts where expressions are considered constant-
expressions.  So is the expression a null pointer constant,
despite not being "constant" in the usual sense?

(Incidentally, "checkout" compiler front-ends are not much
help answering this sort of question if they assume expressions
are never rounding-mode dependent, since they may be
over-optimistic in answering [4.10]'s question as to whether
an expression is constant or not.)



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: Martin von Loewis <loewis@informatik.hu-berlin.de>
Date: Thu, 1 Nov 2001 16:09:35 GMT
Raw View
"Al Grant" <tnarga@arm.REVERSE-NAME.com> writes:

> [5.19] defines constant-expressions and lists where they
> are used.  It says that the cases in which expressions are
> "considered" as constant-expressions are, generally,
> static initializers [3.6.2] and for integer type:
>
>   array bounds
>   case
>   bit-field lengths
>   enum initializers
>   static member initializers
>   template arguments
>
> That is, whether an expression is "considered" as a
> constant-expression depends on the context.

No. These are the contexts where it matters whether a
conditional-expression is a constant-expression (because you cannot
tell syntactically).

> For example, a pointer expression "considered" as a
> constant-expression would need to be an address constant or a null
> pointer constant.

What is a "pointer expression"? If you mean "an expression of pointer
type", then your statement is wrong: a null pointer constant has
integer type, not pointer type.

> [5.19] explicitly says that a pointer expression is considered a
> constant-expression *only* for the purpose of non-local static
> object initialization, implying that in other contexts expressions
> are never constant-expressions.

I cannot see where 5.19 talks about "pointer expressions", only about
"address constant expressions", "null pointer values", and "pointer to
member constant expressions".

> But [4.10] says that "a null pointer constant is an integral
> constant-expression (5.19) rvalue of integer type that
> evaluates to zero".  This surely isn't right.

It definitely is right.

> [5.19] defines the _contexts_ where an expression is considered a
> constant-expression, and states the acceptable expressions in those
> contexts.  It does _not_ define whether an expression is a
> constant-expression, or not, on the basis of its content.

It sure does. 5.19/1 says

# An integral constant-expression can involve only literals (2.13),
# enumerators, const variables or static data members of integral or
# enumeration types initialized with constant expressions (8.5),
# non-type tem-plate parameters of integral or enumeration types, and
# sizeof expressions. Floating literals (2.13.3) can appear only if
# they are cast to integral or enumeration types. Only type
# conversions to integral or enumera-tion types can be used. In
# particular, except in sizeof expressions, functions, class objects,
# pointers, or references shall not be used, and assignment,
# increment, decrement, function-call, or comma operators shall not be
# used.

5.19/2 or later talks about expressions which are not "integral
constant-expressions" but may still be "constant-expressions".

> The logical reading of [4.10] and [5.19] together is that
> null pointer constants, being constant-expressions, only
> occur in static initializers.

Not at all. 5.19/2 is only about non-integral constant expressions.

> Does that mean that there are certain other contexts in which
> expressions are constant-expressions for the purposes of being
> null pointer constants?

You can tell whether an expression is an integral constant-expression
by just looking at the expression itself, independent from context.

> For example: "one side of a relational
> operator where the other side is of pointer type"?  Is it
> possible to list these contexts exhaustively?

Any place where an expression is allowed is potentially an integral
constant-expression.

> As an example of why this matters, consider whether
>
>   static_cast<int>(0.5f)
>
> is an integral constant-expression.

This is certainly an integral constant expression. It involves only a
floating literal that is cast to integral type.

> [4.8] says the value resulting from this cast is an
> implementation-defined choice of 0 or 1.

That is an interesting observation.

> So is the expression a null pointer constant, despite not being
> "constant" in the usual sense?

A null pointer constant must evaluate to zero. Since it is
implementation-defined whether this expression evaluates to zero, it
also appears to be implementation-defined whether it is a null pointer
constant.

> (Incidentally, "checkout" compiler front-ends are not much
> help answering this sort of question if they assume expressions
> are never rounding-mode dependent, since they may be
> over-optimistic in answering [4.10]'s question as to whether
> an expression is constant or not.)

Notice that the freedom given in 4.8 is much broader. An
implementation may chose that static_cast<int>(0.1) evaluates to 1.
Most implementations chose to perform truncation when converting float
to int, so they can easily compute statically that the cast gives 0,
without consideration of rounding modes.

Regards,
Martin

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: Ron Natalie <ron@sensor.com>
Date: Thu, 1 Nov 2001 16:09:24 GMT
Raw View

Al Grant wrote:

> That is, whether an expression is "considered" as a
> constant-expression depends on the context.

Correct, there are flavors of constant-expessions.
The integral-or-enum type that can be used for those
things listed in the first paragraph of 5.19,
and a broader category (includes other arithmatic
and pointer values) that can be used for initialization.

>  For example,
> a pointer expression "considered" as a constant-expression
> would need to be an address constant or a null pointer
> constant.  [5.19] explicitly says that a pointer expression
> is considered a constant-expression *only* for the purpose
> of non-local static object initialization, implying that in
> other contexts expressions are never constant-expressions.

Right, it those cases, pointers are NOT allowed, only integers
and enums.

>
> But [4.10] says that "a null pointer constant is an integral
> constant-expression (5.19) rvalue of integer type that
> evaluates to zero".  This surely isn't right.  [5.19] defines
> the _contexts_ where an expression is considered a
> constant-expression, and states the acceptable expressions
> in those contexts.  It does _not_ define whether an expression
> is a constant-expression, or not, on the basis of its content.
> The logical reading of [4.10] and [5.19] together is that
> null pointer constants, being constant-expressions, only
> occur in static initializers.

The null pointer constant is an INTEGER constant-expression.  It
fits into either category of constant expresions in 5.19.

Null pointer constants are specifically NOT pointers (unless you
cast them to some pointer type), at which point they cease to be
useful for things that require the integer-or-enum constant
expressions.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Al Grant" <tnarga@arm.REVERSE-NAME.com>
Date: Thu, 1 Nov 2001 19:45:15 GMT
Raw View
"Martin von Loewis" <loewis@informatik.hu-berlin.de> wrote in message
news:j4lmhqpj7j.fsf@informatik.hu-berlin.de...
> "Al Grant" <tnarga@arm.REVERSE-NAME.com> writes:
> > For example, a pointer expression "considered" as a
> > constant-expression would need to be an address constant or a null
> > pointer constant.
>
> What is a "pointer expression"? If you mean "an expression of pointer
> type", then your statement is wrong: a null pointer constant has
> integer type, not pointer type.

I mean an expression that needs to produce a pointer value
(possibly from a null pointer constant).

I misread the standard.  4.9 says float to int always truncates.
So static_cast<int>(0.1f) has to be 0.  If that means that an
expression that looks like an integral constant-expression always
_is_ constant (even at runtime), then there is no need to make
the distinction I was trying to make.




---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Al Grant" <tnarga@arm.REVERSE-NAME.com>
Date: Thu, 1 Nov 2001 19:50:04 GMT
Raw View
What is a null pointer constant?

(4.10): "a null pointer constant is an integral constant expression
(5.19) rvalue of integer type that evaluates to zero".

So what is "an integral constant expression (5.19)"?  (5.19) defines
constant-expressions in terms of specific contexts, which it
enumerates.  It defines various contexts for integral constant-
expressions (array bounds, template arguments etc.) and for other
constant-expressions.  Specifically, "other expressions are
considered constant-expressions only for the purpose of non-local
static object initialization".  Note the word "only".  It then
defines certain rules for what is acceptable as a constant-
expression.  It does _not_ say that any expression looking like
that is a constant-expression.  It just says that _if_ an
expression is being "considered" as a constant-expression, _then_
it must look like that.

Nowhere does (5.19) mention general pointer operations as contexts
which consider expressions as constant-expressions.  The null
pointer value is mentioned as a legal pointer value for non-local
static object initialization.

So how can (4.10) and (5.19) be read consistently?  The definition of
constant-expression in (5.19) is top-down.  A constant-expression is
the expression acceptable in a particular context - an array bounds
specification or 'case' label, perhaps.  But in (4.10), the term is
used as a bottom-up context-free predicate on expressions in general.
Certainly (4.10) does not define any contexts for null pointer
constants.  But it is presumably not intended that the only valid
context for a null pointer constant is as a static initializer, which
is the logical reading of (4.10) and (5.19).

There are plenty of contexts where a null pointer constant is valid
but which are not constant-expression contexts.  Is the intention of
(4.10) that in such a context, if an integer valued expression occurs,
it must be an integral constant-expression?  What are the contexts
where this is the case?

To see why this matters, consider

  #define FCON (static_cast<int>(0.5f))

Is this a null pointer constant?  Its value is implementation-defined,
either 0 or 1.  A realistic implementation, following current C, would
define it as 0 at compile-time and as 0 or 1 at runtime depending on
rounding mode.  So we can say that as a constant-expression - i.e. in
a constant-expression context, such as a 'case' label - it is a valid
constant-expression, with value 0.  But as a general expression, it is
not a constant.

In

  if (p == FCON)

whether FCON is a null pointer constant - and indeed a constant
in general - should depend on whether p has integer or pointer type.
(4.10) should make this explicit and enumerate the contexts for which
this is true.

(Comeau C++ accepts it, but that may be simply because it doesn't test
for rounding-mode dependencies and thinks FCON is an expression whose
value is constant, so there is no problem with treating it as a
"constant-expression (5.19)" as required by (4.10).  In a numerically
aware compiler, FCON might be an expression that is constant in a
constant-expression context, and not otherwise.)



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]