Re: Why is this code valid C++?

From: Jack Klein (jackklein_at_spamcop.net)
Date: 02/11/05


Date: Thu, 10 Feb 2005 23:17:02 -0600

On Thu, 10 Feb 2005 17:38:13 -0500, Victor Bazarov
<v.Abazarov@comAcast.net> wrote in comp.lang.c++:

> James Aguilar wrote:
> > Someone showed me something today that I didn't understand. This doesn't
> > seem like it should be valid C++. Specifically, I don't understand how the
> > commas are accepted after the function 'fprintf'. What effect do they have
> > in those parenthesis?
>
> 'exit(0)' is executed. 1 is just for syntactic and semantic correctness,
> since the right operand of || has to have a value and 'exit' doesn't
> return any.
>
> >
> > I understand how the or is useful and why never to do it, I'm really just
> > asking about that construction "(fprintf(stderr, "Can't open file.\n"),
> > exit(0), 1))".
> >
> > ---- CODE ----
> >
> > #include <stdlib.h>
> > #include <stdio.h>
> >
> > int main()
> > {
> > FILE *fp = (FILE *) (fopen("file","r") ||
> > (fprintf(stderr, "Can't open file.\n"), exit(0), 1));
> > return 0;
> > }
> >
> > ---- /CODE ----
>
> It's not valid C++. It's valid C90. But it's very close to being valid
> C++, though.
>
> The || operator causes the evaluation of the left operand. If the result
> of that evaluation is not zero (and in this case if 'fopen' returns a non-
> null pointer), the evaluation stops. HOWEVER, 'fp' may simply get a wrong
> value. Once the left side of || is non-zero, it _may_ be converted (and
> should be converted) to a bool value, which is 'true'. After that the
> same 'true' is cast back to (FILE*), which causes undefined behaviour.

No, it does not, this conversion is well defined.

3.9.1 Fundamental types P7: "Types bool, char, wchar_t, and the signed
and unsigned integer types are collectively called integral types."

5.2.10 Reinterpret cast P5: "A value of integral type or enumeration
type can be explicitly converted to a pointer."

And 5.4 Explicit type conversion (cast notation) makes it quite clear
that the C-style case can perform any valid conversions that any C++
cast can.

So the explicit cast of the value 1 or true is valid in either C or
C++, regardless of whether that value has the type bool (C++), int
(C90), or _bool (C99).

The C++ standard in 5.2.10 P5 includes the clause "mappings between
pointers and integers are otherwise implementation-defined.", while I
prefer the C standard's stronger disclaimer:

========
An integer may be converted to any pointer type. Except as previously
specified, the result is implementation-defined, might not be
correctly aligned, might not point to an entity of the referenced
type, and might be a trap representation.
========

In any case, the conversion to pointer is not undefined, but any
attempt to dereference the resulting pointer most certainly is.

-- 
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html


Relevant Pages

  • Re: C variable retyping
    ... whose type is given by the cast. ... >an integer, no conversion is done, and c is used, within the ... In other words, you may take a pointer value, then use a cast to ... which is probably why the C99 folks decided to allow it ...
    (comp.lang.c)
  • Re: writing library functions and pointers?
    ... On the other hand, pre-ANSI, the cast was ... character pointers, the pointer to the containing word was shifted ... should be the same conversion generated by the cast, ... conversion were done by a cast before the assignment. ...
    (comp.lang.c)
  • Re: two meanings of a cast
    ... as a "let's pretend" cast. ... casts can convert a pointer of one type into a pointer ... There's another such conversion on line four, ... cast converts the value `' to a different type. ...
    (comp.lang.c)
  • Re: writing library functions and pointers?
    ... On the other hand, pre-ANSI, the cast was ... character pointers, the pointer to the containing word was shifted ... should be the same conversion generated by the cast, ... conversion were done by a cast before the assignment. ...
    (comp.lang.c)
  • Re: integer to pinter conversion
    ... While an integer may be converted to a pointer, ... you don't even need the cast in the code above. ... Since the return type is void *, so if the function funcreturns ... conversion is still being done. ...
    (comp.lang.c)