Topic: Some iostream strangeness


Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Sun, 25 Sep 1994 22:06:07 GMT
Raw View
In article <JASON.94Sep20140229@deneb.cygnus.com> jason@cygnus.com (Jason Merrill) writes:
>>>>>> Fergus Henderson <fjh@munta.cs.mu.OZ.AU> writes:
>
>> It turned out that g++ already considered `(void *)0' as a null pointer
>> constant in that it allowed conversion from `(void *)0' to other pointer
>> types, contrary to the ARM. (Why, I don't know for sure; perhaps it was
>> an accidental bug).
>
>For a number of reasons, that have been hashed out in the NULL debate
>before.  One reason is that this way NULL is a pointer rather than an
>integer; this affects overloading, as the original poster found out.
>Another reason is that (void *) and int are different sizes on some
>machines (e.g. alpha) and so passing NULL to ... will wreak havoc on
>implementations where NULL is 0.

I think you've made two very good points Jason, both of which would seem
to provide good cause for the committee give serious consideration to
the incorporation into the standard of some form of universal null pointer
(which is _not_ spelled the same way as the integer literal zero).

(The idea of a universal null pointer has certainly been knocked around
before in both the comp.std.c++ _and_ the comp.std.c newsgroups, but I
cannot recall having ever seen the case for such a thing having been
made quite so well or succinctly as it has been here.  Thank you Jason!)

>> But I still don't see how this explains the behaviour described by
>> the original poster, since `cin >> (void *)0' should give similar
>> results to `cin >> 0' anyway.
>
>It explains the behavior because cin >> NULL is ambiguous and
>cin >> 0 is not; cin >> NULL can match any of the several pointer
>extractors, whereas cin >> 0 unambiguously matches the int extractor.

Ummm... But shouldn't the int extractor be declared to take a parameter
of type `int&'?  If so, then why does your int extractor allow a (non-lvalue)
literal as its argument?  Is this a botch in the argument matching code
of your compiler, or a botch in the declaration of the int extractor in
your library?

--

-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -




Author: jason@cygnus.com (Jason Merrill)
Date: Mon, 26 Sep 1994 02:14:36 GMT
Raw View
>>>>> Ronald F Guilmette <rfg@netcom.com> writes:

> In article <JASON.94Sep20140229@deneb.cygnus.com> jason@cygnus.com (Jason Merrill) writes:
>>>>>>> Fergus Henderson <fjh@munta.cs.mu.OZ.AU> writes:

>>> But I still don't see how this explains the behaviour described by
>>> the original poster, since `cin >> (void *)0' should give similar
>>> results to `cin >> 0' anyway.

>> It explains the behavior because cin >> NULL is ambiguous and
>> cin >> 0 is not; cin >> NULL can match any of the several pointer
>> extractors, whereas cin >> 0 unambiguously matches the int extractor.

> Ummm... But shouldn't the int extractor be declared to take a parameter
> of type `int&'?

It is.

> If so, then why does your int extractor allow a (non-lvalue) literal as
> its argument?

*As I said earlier in this thread*, it doesn't.  Not in pedantic mode,
anyway.  The compiler selects istream::operator>>(int&), but complains when
it tries to call it.  Admittedly, as of the January WP the function should
be rejected at the point of selecting viable functions:

  13.2.3.1.4  Reference binding                           [over.ics.ref]

2 A standard conversion sequence cannot be formed if it requires binding
  a reference to non-const to an rvalue (except when binding an implicit
  object  parameter;  see  the  special   rules   for   that   case   in
  _over.match.funcs_).   This means, for example, that a candidate func-
  tion cannot be a viable function  if  it  has  a  non-const  reference
  parameter  (other  than  the implicit object parameter) and the corre-
  sponding argument is a temporary or would require one to be created to
  initialize the reference (see _dcl.init.ref_).

But the result in this case is the same.  Out of curiosity, do any
compilers currently implement this rule?  In other words, do they accept
code like

void f (int&);
void f (int, int=0);

main()
{
  f(1);
}

?  g++ 2.6.0, Cfront 3.0.1 and xlC 1.3 all complain that the call is
ambiguous.

Jason




Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Sat, 24 Sep 1994 07:59:05 GMT
Raw View
In article <1994Sep19.170011.22189@csc.canberra.edu.au> tp941821@gum.canberra.edu.au writes:
>
>Hi,
> I was looking for some way to read a line, and then discard it.
>Here's what I came up with :
>
> cin >> NULL;
>
>which doesn't work for obvious reasons; but then, for curiosity reasons
>I tried out :-
>
> cin >> 0;
>
>Which surprisingly did the job! which is a bit strange don't you think ?

Yes.  I do think.

Unless I'm mistaken, the second operand of the iostream >> operator should
require an lvalue... which the literal `0' isn't, so I'm a bit surprized
that you could even compile that.  But perhaps someone more familiar with
iostreams than me (which includes just about everybody) will set me straight.

--

-- Ron Guilmette, Sunnyvale, CA ---------- RG Consulting -------------------
---- domain addr: rfg@netcom.com ----------- Purveyors of Compiler Test ----
---- uucp addr: ...!uunet!netcom!rfg ------- Suites and Bullet-Proof Shoes -




Author: kanze@us-es.sel.de (James Kanze US/ESC 60/3/164 #71425)
Date: 20 Sep 1994 16:36:37 GMT
Raw View
In article <1994Sep19.170011.22189@csc.canberra.edu.au>
tp941821@gum.canberra.edu.au writes:

|>  I was looking for some way to read a line, and then discard it.
|> Here's what I came up with :

|>  cin >> NULL;

|> which doesn't work for obvious reasons;

I suspect that the reasons are anything less than obvious.  In C++,
NULL is *required* to be defined as an integral constant evalutating
to 0.  NULL is *not* a pointer.

|> but then, for curiosity reasons
|> I tried out :-

|>  cin >> 0;

|> Which surprisingly did the job! which is a bit strange don't you think ?
|> Any ideas ?? ( used gnu c++ for SunOS ).

The compiler is broken:-).

|> Is this consistent with the c++ standard ?

No.  But the error (both with NULL and 0) is due to a violation of
const-ness, and g++ is (or was, I haven't used it lately) notoriously
lax in this area.

Of the two examples, and given the choice of compiler, I am more
surprised that the first didn't work, than that the second did.  Or
did Cygnus add Fergus' modification for a real NULL pointer?  (Three
cheers for them if they did.)
--
James Kanze      Tel.: (+33) 88 14 49 00     email: kanze@lts.sel.alcatel.de
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils en informatique industrielle --
                              -- Beratung in industrieller Datenverarbeitung






Author: jason@cygnus.com (Jason Merrill)
Date: Tue, 20 Sep 1994 21:02:29 GMT
Raw View
>>>>> Fergus Henderson <fjh@munta.cs.mu.OZ.AU> writes:

> It turned out that g++ already considered `(void *)0' as a null pointer
> constant in that it allowed conversion from `(void *)0' to other pointer
> types, contrary to the ARM. (Why, I don't know for sure; perhaps it was
> an accidental bug).

For a number of reasons, that have been hashed out in the NULL debate
before.  One reason is that this way NULL is a pointer rather than an
integer; this affects overloading, as the original poster found out.
Another reason is that (void *) and int are different sizes on some
machines (e.g. alpha) and so passing NULL to ... will wreak havoc on
implementations where NULL is 0.

> But I still don't see how this explains the behaviour described by
> the original poster, since `cin >> (void *)0' should give similar
> results to `cin >> 0' anyway.

It explains the behavior because cin >> NULL is ambiguous and
cin >> 0 is not; cin >> NULL can match any of the several pointer
extractors, whereas cin >> 0 unambiguously matches the int extractor.

Jason




Author: jason@cygnus.com (Jason Merrill)
Date: Tue, 20 Sep 1994 18:16:53 GMT
Raw View
>>>>> James Kanze US/ESC 60/3/164 #71425 <kanze@us-es.sel.de> writes:

> No.  But the error (both with NULL and 0) is due to a violation of
> const-ness, and g++ is (or was, I haven't used it lately) notoriously
> lax in this area.

g++ is actually pretty good about checking const correctness now.  For that
code, 2.6.0 complains

wa.C:7: warning: initialization of non-const `int &' from rvalue `int'
/deneb/blob/jason/g++/small/devo/libio/iostream.h:187: warning: in passing argument 1 of `istream::operator >>(int &)'

Using -pedantic-errors will change the warnings to errors.

> Of the two examples, and given the choice of compiler, I am more
> surprised that the first didn't work, than that the second did.  Or
> did Cygnus add Fergus' modification for a real NULL pointer?

Yes, g++ uses ((void*)0) for NULL.

Jason




Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Tue, 20 Sep 1994 18:43:33 GMT
Raw View
kanze@us-es.sel.de (James Kanze US/ESC 60/3/164 #71425) writes:

>tp941821@gum.canberra.edu.au writes:
>
>|> I was looking for some way to read a line, and then discard it.
>|> Here's what I came up with :
>
>|>  cin >> NULL;
>
>|> which doesn't work for obvious reasons;
>
>I suspect that the reasons are anything less than obvious.

Indeed.  When I tried it on using g++ on SunOS, I got a somewhat
suprising *link-time* error message - undefined reference to _strtoul!!!

The reason for this is that (a) I was using g++ 2.5.7, which doesn't
detect the erroroneous initialization of a reference with a non-lvalue
[2.6.0 gets it right] and (b) the SunOS library I was using was the
non-ANSI one, which doesn't include strtoul(), and presumeably
istream::operator>>(int&) is implemented using strtoul().

>|> but then, for curiosity reasons
>|> I tried out :-
>
>|>  cin >> 0;
>
>|> Which surprisingly did the job! which is a bit strange don't you think ?
>|> Any ideas ?? ( used gnu c++ for SunOS ).

I couldn't duplicate this.  I got the same link error described above.
(g++ 2.5.7, SunOS 4.1.3).

>The compiler is broken:-).
>
>|> Is this consistent with the c++ standard ?
>
>No.  But the error (both with NULL and 0) is due to a violation of
>const-ness, and g++ is (or was, I haven't used it lately) notoriously
>lax in this area.

2.6.0 is a lot better.

>Of the two examples, and given the choice of compiler, I am more
>surprised that the first didn't work, than that the second did.  Or
>did Cygnus add Fergus' modification for a real NULL pointer?  (Three
>cheers for them if they did.)

It turned out that g++ already considered `(void *)0' as a null pointer
constant in that it allowed conversion from `(void *)0' to other
pointer types, contrary to the ARM. (Why, I don't know for sure;
perhaps it was an accidental bug).  This meant that there was no need
for __builtin_null_pointer, because you could use `#define NULL (void *)0'.

By another amazing coincidence, at least as of g++/libg++ 2.6, 2.5 and maybe
earlier, <stddef.h> defines NULL as `(void*)0' even for C++. (Again, I
don't think this was deliberate, I suspect it was a purely accidental
bug which was never detected due to the aforementioned bug/feature.)
I think the definition of NULL in the other system header files is the
same as what was in your original C headers.

So with g++, NULL *is* a real null pointer constant - if you
#include <stddef.h> first.  If you #include one of the other header
files that defines NULL first, then it's probably not.

But I still don't see how this explains the behaviour described by
the original poster, since `cin >> (void *)0' should give similar
results to `cin >> 0' anyway.

--
Fergus Henderson - fjh@munta.cs.mu.oz.au




Author: tp941821@gum.canberra.edu.au
Date: Mon, 19 Sep 94 17:00:11 GMT
Raw View
Hi,
 I was looking for some way to read a line, and then discard it.
Here's what I came up with :

 cin >> NULL;

which doesn't work for obvious reasons; but then, for curiosity reasons
I tried out :-

 cin >> 0;

Which surprisingly did the job! which is a bit strange don't you think ?
Any ideas ?? ( used gnu c++ for SunOS ).
Is this consistent with the c++ standard ?


-=Tushar-Pokle-=-=-(+616-2015201)-=-=-=-=-