Topic: Comments on C++ Draft Standard
Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/05/26 Raw View
"Paul D. DeRocco" <pderocco@strip_these_words.ix.netcom.com> writes:
|> James Kanze wrote:
|> >
|> > "Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com> writes:
|> >
|> > |> But is there really any sense in which falling off the end without a
|> > |> return is more undefined than returning an uninitialized value?
|> > |>
|> > |> int foo(int x) {
|> > |> int y;
|> > |> if (x) y = 1;
|> > |> return y;
|> > |> }
|> > |>
|> > |> In practice, the result is the same as falling off the end, i.e.,
|> > |> returning a value consisting of whatever bits were in the register or
|> > |> memory location at the time. In more complex cases, the compiler cannot
|> > |> detect the above, and there is nothing it can insert at the end that
|> > |> would guarantee that terminate() is called in the case of returning an
|> > |> uninitialized variable.
|> >
|> > This is fine with int's, and most compilers will do just this (if only
|> > for reasons of backward compatibility). The real problems occur when
|> > the return type is a class, with a constructor and a destructor (and
|> > maybe no default destructor).
|>
|> How can a class not have a default destructor?
A typo. I meant default constructor.
|> > In such cases, I can see no reason for a compiler not generating some
|> > sort of orderly shutdown: a fatal signal, calling terminate or abort,
|> > etc.
|>
|> But what would it take to guarantee that? It seems to me that it is no
|> easier to guarantee for class objects than for ints: the compiler would
|> have to invent a hidden bool, initialized to false, and set to true
|> whenever any code assigns to the object, or passes a non-const pointer
|> or reference to the object to another function. The above would have to
|> be rewritten by the compiler:
|>
|> int foo(int x) {
|> int y;
|> bool yinit = false;
|> if (x) {
|> y = 1;
|> yinit = true;
|> }
|> if (!yinit) terminate();
|> return y;
|> }
No. In this case, 'y' is an object, whether it is initialized or not.
I was concerned about the case where an object has no default
constructor, and there is no return statement at the end. What should
the compiler generate there?
Thus:
T
f( int x )
{
switch ( x )
{
case 1 :
return T( 1 ) ;
case 0 :
return T( 2 ) ;
case -1 :
return T( 3 ) ;
}
// So what should the compiler generate here?
}
Most compilers today simply generate a return instruction, as if there
were no return value. And the program crashes somewhere in the callers
code. It wouldn't take much to generate a jump to a library routine
which output an error message and then did an abort, and this would be
much more helpful in case of error.
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "Paul D. DeRocco" <pderocco@strip_these_words.ix.netcom.com>
Date: 1997/05/22 Raw View
James Kanze wrote:
>
> "Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com> writes:
>
> |> But is there really any sense in which falling off the end without a
> |> return is more undefined than returning an uninitialized value?
> |>
> |> int foo(int x) {
> |> int y;
> |> if (x) y = 1;
> |> return y;
> |> }
> |>
> |> In practice, the result is the same as falling off the end, i.e.,
> |> returning a value consisting of whatever bits were in the register or
> |> memory location at the time. In more complex cases, the compiler cannot
> |> detect the above, and there is nothing it can insert at the end that
> |> would guarantee that terminate() is called in the case of returning an
> |> uninitialized variable.
>
> This is fine with int's, and most compilers will do just this (if only
> for reasons of backward compatibility). The real problems occur when
> the return type is a class, with a constructor and a destructor (and
> maybe no default destructor).
How can a class not have a default destructor?
> In such cases, I can see no reason for a compiler not generating some
> sort of orderly shutdown: a fatal signal, calling terminate or abort,
> etc.
But what would it take to guarantee that? It seems to me that it is no
easier to guarantee for class objects than for ints: the compiler would
have to invent a hidden bool, initialized to false, and set to true
whenever any code assigns to the object, or passes a non-const pointer
or reference to the object to another function. The above would have to
be rewritten by the compiler:
int foo(int x) {
int y;
bool yinit = false;
if (x) {
y = 1;
yinit = true;
}
if (!yinit) terminate();
return y;
}
--
Ciao,
Paul
(Please remove the "strip_these_words." prefix from the return
address, which has been altered to foil junk mail senders.)
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/05/20 Raw View
"Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com> writes:
|> Dag Bruck wrote:
|> >
|> > I wrote a proposal to the C++ standards committee several years ago,
|> > which argued for calling terminate() if a value-returning function
|> > falls off the end. The cost for such an extension (amount of extra
|> > code) is quite small, in particular because the compiler can detect
|> > that the user always returns a value in many cases.
|> >
|> > The standards committee discussed the proposal for a short while and
|> > decided that this was not valuable enough to include in the standard.
|>
|> Snooty bastards. (Just kidding.)
|>
|> But is there really any sense in which falling off the end without a
|> return is more undefined than returning an uninitialized value?
|>
|> int foo(int x) {
|> int y;
|> if (x) y = 1;
|> return y;
|> }
|>
|> In practice, the result is the same as falling off the end, i.e.,
|> returning a value consisting of whatever bits were in the register or
|> memory location at the time. In more complex cases, the compiler cannot
|> detect the above, and there is nothing it can insert at the end that
|> would guarantee that terminate() is called in the case of returning an
|> uninitialized variable.
This is fine with int's, and most compilers will do just this (if only
for reasons of backward compatibility). The real problems occur when
the return type is a class, with a constructor and a destructor (and
maybe no default destructor).
In such cases, I can see no reason for a compiler not generating some
sort of orderly shutdown: a fatal signal, calling terminate or abort,
etc.
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/05/20 Raw View
cwaters@systems.dhl.com (Chris Waters) writes:
|> In article <337cbf3f.45196464@news.ma.ultranet.com>
|> phalpern@truffle.ma.ultranet.com (Pablo Halpern) writes:
|>
|> >James Kanze <james-albert.kanze@vx.cit.alcatel.fr> wrote:
|>
|> >>The amount of code generated is a single instruction: branch to the
|> >>error handling routine in the library. Not very much, IMHO. And the
|> >>compiler has to generate something (a return instruction, at the very
|> >>least).
|>
|> >A return instruction might be as small as one byte, whereas a branch to
|> >a 32-bit address would require at least 5 bytes. Also, an inline
|> >function probably doesn't even have a return instruction. Requiring this
|> >branch would also require that the rest of the code branch around the
|> >branch (in an inline function). The combination could wreak havoc with
|> >branch-predictive caching logic on some CPUs. A very unexpected
|> >performance penalty might result from inserting "code that is never
|> >executed."
|>
|> Furthermore, an exception which simply says "some function somewhere
|> fell off the end" wouldn't be very useful. The original poster
|> actually suggested something along the lines of:
|>
|> throw no_return_exception(__FILE__, __LINE__);
|>
|> This would have a lot more overhead than just one instruction. At the
|> least, you have to store the filename and line number, and have
|> instructions to push them onto the stack (or whatever) and call the
|> exception's constructor.
Well, just saying "Null pointer dereferenced" at the end of execution is
certainly less useful than giving the exact details at the point of
dereferencing, as well. This is a quality of implementation issue, and
user preferences may vary. I'd put this in the same category. (On most
systems, it should be very easy to trigger a core dump; I've never heard
of a system where you couldn't get a complete stack walkback from a core
dump.)
|> A function which appears to fall off the end is either a mistake or
|> tricky code. If the latter, it's most likely to appear in embedded
|> code or someplace similar, e.g. OS kernel code. (If it were to appear
|> anywhere else, then no matter how tricky and deliberate, I'd still
|> call it a mistake!:) *ANY* overhead in such code is often too much!
A function which actually falls off the end is undefined behavior. As
such, the compiler can really do whatever it wants with it. The only
possible overhead is space, and most systems can trigger a core dump in
a single instruction. If the space overhead of a single instruction
makes a difference, you'll be writing the program in assembler anyway,
and not C++/
|> Again, I think this would be wonderful as an optional feature of some
|> compiler, but I think it would be a huge mistake to mandate this
|> exception in the standard.
Agreed. That was basically my point, anyway. The current wording says
undefined behavior, which allows simple, inexpensive (but very useful)
treatment like generating a core dump. If compilers don't do this now,
perhaps one should ask why. (I'm talking here about complex return
types. Regretfully, existing code has some weight, regardless of the
standard, and I don't expect existing compilers to cause a core dump on
falling of the end of a function returning int anytime soon.)
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/05/20 Raw View
Marcelo Cantos <marcelo@mds.rmit.edu.au> writes:
|> phalpern@truffle.ma.ultranet.com (Pablo Halpern) writes:
|>
|> >
|> > James Kanze <james-albert.kanze@vx.cit.alcatel.fr> wrote:
|> >
|> > >
|> > >The amount of code generated is a single instruction: branch to the
|> > >error handling routine in the library. Not very much, IMHO. And the
|> > >compiler has to generate something (a return instruction, at the very
|> > >least).
|> >
|> > A return instruction might be as small as one byte, whereas a branch to
|> > a 32-bit address would require at least 5 bytes. Also, an inline
|> > function probably doesn't even have a return instruction. Requiring this
|> > branch would also require that the rest of the code branch around the
|> > branch (in an inline function). The combination could wreak havoc with
|> > branch-predictive caching logic on some CPUs. A very unexpected
|> > performance penalty might result from inserting "code that is never
|> > executed."
|>
|> By way of explanation, Pablo and James talk different languages. The
|> SPARC architecture which James and I use has 32-bit instructions, end
|> of story. 32-bit values are squeezed into this slot in unusual ways.
|> Pablo (I think) and I use the Intel architecture which is another
|> story altogether, as evidenced above. (Yes, I'm being vain.
|> Disgraceful, isn't it!)
Well, that may be partially it. But I'm also familiar with the Intel
instruction set. (I taught Intel assembler for two years, back when the
architecture was new.)
For a non-inline function, I don't think the 5 bytes vs. 1 byte is
important. How many bytes will this make in the total size of the
program?
For the inline functions, most compilers today will use profiling output
in their optimization, and of course, the profiling output will show
that the jump is rarely taken. So the code will be rearranged so that
the normal path will only contain a conditional (2 byte) jump that is
never taken; the conditional jump will predict correctly 100% of the
time.
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: tony@online.tmx.com.au (Tony Cook)
Date: 1997/05/15 Raw View
Tony Cook (tony@online.tmx.com.au) wrote:
: John David Galt (jdg@rahul.net) wrote:
: : [stmt.return]:
: : a) Flowing off the end of a value-returning function should not produce
: : undefined behavior -- it should make the program ill-formed. This is
: : certainly always detectable at compile time.
: This is the case in the latest draft
As several people have pointed out, I am definitely wrong here - I
don't know what I was thinking when I wrote this!
--
Tony Cook - tony@online.tmx.com.au
100237.3425@compuserve.com
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: phalpern@truffle.ma.ultranet.com (Pablo Halpern)
Date: 1997/05/16 Raw View
Christopher Eltschka <celtschk@physik.tu-muenchen.de> wrote:
>
>what about:
>
>int lookup(int i)
>{
> switch(i)
> {
> case 1: return -1;
> case 2: return 1;
> default: return 0;
> }
>}
This actually obfuscates the code because it does not make it clear that
the only default case is 3. This could cause maintenance problems later,
even if you add a comment.
The various approaches to coding to avoid a compiler diagnostic for
falling off the end of a function adds one more reason why the compiler
should not be required to issue such a diagnostic. Also the different
approaches have different strengths and it seems like it should be the
programmer's option to decide how to handle the issue. Here's one way
that is clear, takes no run-time overhead in non-debug code, and
diagnosis an off-the-end condition only if it actually happens:
const bool notreached = false;
int lookup(int i)
{
switch(i)
{
case 1: return -1;
case 2: return 1;
case 3: return 0;
}
assert(notreached);
}
By putting an "assert(notreached)" at the end of all of my
value-returning functions (except those that obviously end with a return
statement), I get run-time checking for debugging. Asserts get compiled
out in optimized code (with NDEBUG turned on). I don't require that the
compiler generate the run-time checks (although it would be nice if it
were an option on more compilers), and I don't need a change in the
standard.
-------------------------------------------------------------
Pablo Halpern phalpern@truffle.ultranet.com
I am self-employed. Therefore, my opinions *do* represent
those of my employer.
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: dag@net.dynasim.se (Dag Bruck)
Date: 1997/05/16 Raw View
I wrote a proposal to the C++ standards committee several years ago,
which argued for calling terminate() if a value-returning function
falls off the end. The cost for such an extension (amount of extra
code) is quite small, in particular because the compiler can detect
that the user always returns a value in many cases.
The standards committee discussed the proposal for a short while and
decided that this was not valuable enough to include in the standard.
I still think it's too bad we didn't take the trouble of reducing the
number of undefined bahaviours, although it's a small issue. The
discussion on this newsgroup, and the confusion if it's perhaps not
undefined if you never use the return value, could have been avoided.
My interpretation was that the commettee members had to prove at some
point that they said no to a proposal, and this one wasn't important.
Dag Bruck
Dynasim AB
--
Dynasim AB Phone: +46 46 182500
Research Park Ideon Fax: +46 46 182501
S-223 70 Lund E-mail: dag@Dynasim.se
Sweden URL: http://www.Dynasim.se
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: phalpern@truffle.ma.ultranet.com (Pablo Halpern)
Date: 1997/05/16 Raw View
James Kanze <james-albert.kanze@vx.cit.alcatel.fr> wrote:
>
>The amount of code generated is a single instruction: branch to the
>error handling routine in the library. Not very much, IMHO. And the
>compiler has to generate something (a return instruction, at the very
>least).
A return instruction might be as small as one byte, whereas a branch to
a 32-bit address would require at least 5 bytes. Also, an inline
function probably doesn't even have a return instruction. Requiring this
branch would also require that the rest of the code branch around the
branch (in an inline function). The combination could wreak havoc with
branch-predictive caching logic on some CPUs. A very unexpected
performance penalty might result from inserting "code that is never
executed."
-------------------------------------------------------------
Pablo Halpern phalpern@truffle.ultranet.com
I am self-employed. Therefore, my opinions *do* represent
those of my employer.
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/05/17 Raw View
Julian Pardoe <pardoej@lonnds.ml.com> writes:
|> David Chase wrote:
|> >
|> > > Bernard Badger wrote:
|> > > > If C++ completes the definitions of /, %, << and >> by supplying
|> > > > requirements to the undefined parts, then it isn't, technically,
|> > > > incompatible with C.
|> >
|> > This problems (the implementation-definedness of / and %) has annoyed
|> > me for years. The basic cost of hardware division/remainder (not to
|> > be confused with division and remainder in the source code, pre-
|> > optimization) is high enough, and the relative frequency is low enough,
|> > that it will not make a difference to anyone (except perhaps certain
|> > well-known comp.arch curmudgeons) if it costs an extra cycle or two to get
|> > division and remainder "right".
|>
|> Well, some might disagree as to what "right" means.
I think that the rest of David's original posting indicated that there
is, in fact, a general consensus as to what "right" means. "Right"
means what 99% of all hardware currently does.
|> But my question is: Why bother? I have rarely ever used integer / and %
|> with negative numbers and have had little cause to care what their
|> behaviour is. When it has mattered I have wrapped the operation is a
|> small and well commented function.
Well, one of the reasons I've rarely used integer / and % with negative
numbers is precisely that it isn't well defined. However, it means that
whenever I use integer / and %, I have an additional condition to check,
in order to verify that my software is correct.
More importantly, of course, is that I might forget to check it. Or I
might have an error in my reasoning when checking it. And if round to
zero happens to be correct for my application, I will not be able to
detect the error by testing, either, at least not on my platforms. And
that by the time the software gets ported to one of the rare platforms
where it works differently, no one will really remember the logic of the
program any longer, so finding the error will be a real pain.
The problem is reproducibility: if my code works here, it will work
there.
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: cwaters@systems.dhl.com (Chris Waters)
Date: 1997/05/17 Raw View
In article <337cbf3f.45196464@news.ma.ultranet.com>
phalpern@truffle.ma.ultranet.com (Pablo Halpern) writes:
>James Kanze <james-albert.kanze@vx.cit.alcatel.fr> wrote:
>>The amount of code generated is a single instruction: branch to the
>>error handling routine in the library. Not very much, IMHO. And the
>>compiler has to generate something (a return instruction, at the very
>>least).
>A return instruction might be as small as one byte, whereas a branch to
>a 32-bit address would require at least 5 bytes. Also, an inline
>function probably doesn't even have a return instruction. Requiring this
>branch would also require that the rest of the code branch around the
>branch (in an inline function). The combination could wreak havoc with
>branch-predictive caching logic on some CPUs. A very unexpected
>performance penalty might result from inserting "code that is never
>executed."
Furthermore, an exception which simply says "some function somewhere
fell off the end" wouldn't be very useful. The original poster
actually suggested something along the lines of:
throw no_return_exception(__FILE__, __LINE__);
This would have a lot more overhead than just one instruction. At the
least, you have to store the filename and line number, and have
instructions to push them onto the stack (or whatever) and call the
exception's constructor.
A function which appears to fall off the end is either a mistake or
tricky code. If the latter, it's most likely to appear in embedded
code or someplace similar, e.g. OS kernel code. (If it were to appear
anywhere else, then no matter how tricky and deliberate, I'd still
call it a mistake!:) *ANY* overhead in such code is often too much!
Again, I think this would be wonderful as an optional feature of some
compiler, but I think it would be a huge mistake to mandate this
exception in the standard.
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Marcelo Cantos <marcelo@mds.rmit.edu.au>
Date: 1997/05/17 Raw View
phalpern@truffle.ma.ultranet.com (Pablo Halpern) writes:
> Christopher Eltschka <celtschk@physik.tu-muenchen.de> wrote:
[snip]
> const bool notreached = false;
>
> int lookup(int i)
> {
> switch(i)
> {
> case 1: return -1;
> case 2: return 1;
> case 3: return 0;
> }
> assert(notreached);
> }
(sorry about the excessive snipping. My news feed is a bit picky.)
Actually I use:
assert(!"YOU IDIOT!!!!!!!");
or some other appropriate comment (note that the number of exclamation
marks is extremely unimportant!!!). Frankly, I don't actually know if
it's legal to logically negate a pointer; any takers?
(Actually, my assertions are never this acerbic. It is always
conceivable that one of them might pop up on the clients desk.)
--
______________________________________________________________________
Marcelo Cantos, Research Assistant __/_ marcelo@mds.rmit.edu.au
Multimedia Database Systems Group, RMIT / _ Tel 61-3-9282-2497
723 Swanston St, Carlton VIC 3053 Aus/ralia ><_> Fax 61-3-9282-2490
Acknowledgements: errors - me; wisdom - God; funding - RMIT
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Marcelo Cantos <marcelo@mds.rmit.edu.au>
Date: 1997/05/17 Raw View
phalpern@truffle.ma.ultranet.com (Pablo Halpern) writes:
>
> James Kanze <james-albert.kanze@vx.cit.alcatel.fr> wrote:
>
> >
> >The amount of code generated is a single instruction: branch to the
> >error handling routine in the library. Not very much, IMHO. And the
> >compiler has to generate something (a return instruction, at the very
> >least).
>
> A return instruction might be as small as one byte, whereas a branch to
> a 32-bit address would require at least 5 bytes. Also, an inline
> function probably doesn't even have a return instruction. Requiring this
> branch would also require that the rest of the code branch around the
> branch (in an inline function). The combination could wreak havoc with
> branch-predictive caching logic on some CPUs. A very unexpected
> performance penalty might result from inserting "code that is never
> executed."
By way of explanation, Pablo and James talk different languages. The
SPARC architecture which James and I use has 32-bit instructions, end
of story. 32-bit values are squeezed into this slot in unusual ways.
Pablo (I think) and I use the Intel architecture which is another
story altogether, as evidenced above. (Yes, I'm being vain.
Disgraceful, isn't it!)
--
______________________________________________________________________
Marcelo Cantos, Research Assistant __/_ marcelo@mds.rmit.edu.au
Multimedia Database Systems Group, RMIT / _ Tel 61-3-9282-2497
723 Swanston St, Carlton VIC 3053 Aus/ralia ><_> Fax 61-3-9282-2490
Acknowledgements: errors - me; wisdom - God; funding - RMIT
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com>
Date: 1997/05/17 Raw View
Dag Bruck wrote:
>
> I wrote a proposal to the C++ standards committee several years ago,
> which argued for calling terminate() if a value-returning function
> falls off the end. The cost for such an extension (amount of extra
> code) is quite small, in particular because the compiler can detect
> that the user always returns a value in many cases.
>
> The standards committee discussed the proposal for a short while and
> decided that this was not valuable enough to include in the standard.
Snooty bastards. (Just kidding.)
But is there really any sense in which falling off the end without a
return is more undefined than returning an uninitialized value?
int foo(int x) {
int y;
if (x) y = 1;
return y;
}
In practice, the result is the same as falling off the end, i.e.,
returning a value consisting of whatever bits were in the register or
memory location at the time. In more complex cases, the compiler cannot
detect the above, and there is nothing it can insert at the end that
would guarantee that terminate() is called in the case of returning an
uninitialized variable.
--
Ciao,
Paul
(Please remove the "strip_these_words_" prefix from the return
address, which has been altered to foil junk mail senders.)
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: d96-mst@nada.kth.se (Mikael Steldal)
Date: 1997/05/18 Raw View
In article <337683ef.180743585@nntp.ix.netcom.com>,
miker3@ix.netcom.com (Mike Rubenstein) wrote:
>> No. All such switch statements must have a default clause.
>
>I can't find that in the draft -- could you please give me a
>reference.
Sorry, I mean with my proposal.
> default:
> handle_impossible_error();
Can be handled with the noreturn proposal.
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: miker3@ix.netcom.com (Mike Rubenstein)
Date: 1997/05/10 Raw View
Alexandre Oliva <oliva@dcc.unicamp.br> wrote:
> Mike Rubenstein writes:
>
> > Alexandre Oliva <oliva@dcc.unicamp.br> wrote:
>
> >> I'd create a standard exception such as std::no_return_exception and
> >> get the compiler implicitly generate:
>
> >> throw std::no_return_exception(__FILE__, __LINE__);
>
> > I think the standard exception idea has merit. While it would break
> > some now legal code, I don't think this would be a great burden.
>
> How would it break legal code? It would only be inserted in functions
> that might fall off the end, and this is illegal code.
Whoops. You're right -- for some reason I was thinking of C where it
is legal to fall off the end of a function that returns a value.
Michael M Rubenstein
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: d96-mst@nada.kth.se (Mikael Steldal)
Date: 1997/05/10 Raw View
In article <336FDD58.156C@alum.mit.edu>,
Gerard Weatherby <gerardw@alum.mit.edu> wrote:
> default:
> throw "bad value";
> return 0; /* obviously, this never really executes, but I had
> to put it in because the compiler requires it */
throw should be a acceptable alternative for return.
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/05/11 Raw View
Max TenEyck Woodbury <mtew@cds.duke.edu> writes:
> Gerard Weatherby wrote:
> >
> > Paul D. DeRocco wrote:
> > -
> > - Pablo Halpern wrote:
> > - >
> > - > int lookup(int i)
> > - > {
> > - > switch (i)
> > - > {
> > - > case 1: return -1;
> > - > case 2: return 1;
> > - > case 3: return 0;
> > - > }
> > - > }
> > - >
> > - > The compiler doesn't know if 1, 2 or 3 are the only possible values
> > - > for i.
[...]
> > - In this case, I would expect the compiler to analyze it from the point
> > - of view of that i could be any int, and issue an error or warning. It
> > - would be up to me to quiet this error by putting in a default case.
A program should be well-formed or not in itself, this shouldn't
depend on some optimisation level/compiler switch/the choice of
compiler; this is nearly (not absolutly) the case today.
So the compiler can issue a warning but not an error:
int i = 0;
const int ci = 0;
int j = 1/i; // a good compiler with optimisation on will issue
// a warning but isn't allowed to issue an error
int cj = 1/ci; // error here
> > So you add,
> > case 3: return 0;
> > default: return 0; /*this never really executes, but I had
> > to put it in because the compiler requires it */
I want to cry. I hope it's a joke.
> > or
> > case 3: return 0;
> > default:
> > throw "bad value";
> > return 0; /* obviously, this never really executes, but I had
> > to put it in because the compiler requires it */
> > ??
> > IMO, having additional non-executing code to hush the compiler is a
> > waste and detracts from the readability of the program. I'd rather see:
Not only a waste, it's absolutly awfull.
> > case 3: return 0;
> > default: asset(0);
> > or
> > case 3: return 0;
> > default:
> > throw "bad value";
> > }
Not too bad (that's the ML way).
> but the following also works and doesn't produce extra code or require
> (too much) explination:
>
> default: /* bad input case */
> case 3: return 0;
>
The worst thing you can do ! I prefer to reach the end of the
function without a return (at least I get a chance to crash
the whole system).
What about:
switch (i)
{
case 1: return -1;
case 2: return 0;
case 3: return 1;
no_default;
}
or
switch (i)
{
case 1: return -1;
case 2: return 0;
case 3: return 1;
default: never_reach;
}
In Ada flowing of a function raise a Program_error; in C/C++ we
(usually) translate 'undefined behaviour'.
Should we introduce run-time checks here ? That a philosophic
issue: 'undefined' let some compiler insert checks and other
optimise; the programmer know that anyway he shouldn't do that.
One can argue that there is no time cost, only space; but space
might be an issue with embeded software (ok these compilers will
certainly be non std anyway because they will allow EH to be
disabled) and it could affect locality.
--
Valentin Bonnard
mailto:bonnardv@pratique.fr
http://www.pratique.fr/~bonnardv (Informations sur le C++ en Francais)
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/05/11 Raw View
videoman@tiac.net (Videoman) writes:
>May I suggest something here? I have been thinking of something
>similar for quite some time - user attribute tags. (This is an
>expression of the general concept of objects/attributes and
>association, applied to the C/C++ programming domain.)
The devil is in the details. You suggested some syntax, but
you didn't indicate what the semantics of that syntax would be.
Your proposal is IMHO too under-specified for anyone to give much
in the way of useful feedback on it.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Gerard Weatherby <gerardw@alum.mit.edu>
Date: 1997/05/11 Raw View
Max TenEyck Woodbury wrote:
-
- Gerard Weatherby wrote:
<excess snipped-
- - IMO, having additional non-executing code to hush the compiler is a
- - waste and detracts from the readability of the program. I'd rather
see:
- - case 3: return 0;
- - default: asset(0);
- - or
- - case 3: return 0;
- - default:
- - throw "bad value";
- - }
-
- but the following also works and doesn't produce extra code or require
- (too much) explination:
-
- default: /* bad input case */
- case 3: return 0;
-
- mtew@cds.duke.edu
If the input argument is (for example) 4, returning 0 is incorrect
behavior, and will likely lead to hard to debug errors. If the caller
violates
the "contract" of the function, ANY return value is wrong. So the
function shouldn't return.
I don't have any objection to a warning, as long it can be supressed; I
didn't think it should be a requirement of the language, tho'.
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: d96-mst@nada.kth.se (Mikael Steldal)
Date: 1997/05/11 Raw View
In article <336e56ed.13312993@nntp.ix.netcom.com>,
miker3@ix.netcom.com (Mike Rubenstein) wrote:
>How can the compiler tell? for example if is defined as
>
> int g(i) { return 1; }
>
>then it is impossible for the compiler to determine that f(int) cannot
>fall off the end unless it sees the definition of g(int).
Sorry, I don't understand this example at all. How is f() and g() related?
>Another problem. Consider the code
>
> int f(int i)
> {
> switch (abs(i) % 5)
> {
> case 0:
> case 1:
> return 7;
>
> case 2:
> case 3:
> return 12;
>
> case 4:
> return 2;
> }
> }
>
>Do we require the compiler analyze the matematics to determine that
>these are the only possible cases?
No. All such switch statements must have a default clause.
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: miker3@ix.netcom.com (Mike Rubenstein)
Date: 1997/05/08 Raw View
Alexandre Oliva <oliva@dcc.unicamp.br> wrote:
> Mike Rubenstein wrote:
>
> > then it is impossible for the compiler to determine that f(int) cannot
> > fall off the end unless it sees the definition of g(int).
>
> > How do you word the requirement to avoid this problem?
>
> I'd create a standard exception such as std::no_return_exception and
> get the compiler implicitly generate:
>
> throw std::no_return_exception(__FILE__, __LINE__);
> or
> abort();
>
> wherever it might be possible for a non-void function to fall off the
> end.
I'd be against having it call abort -- that just doesn't give enough
information to be useful. While this wouldn't, in practice, require
much (space) overhead, I don't see any point in any overhead if it
isn't useful
I think the standard exception idea has merit. While it would break
some now legal code, I don't think this would be a great burden.
Note that in practice the overhead introduced by a decent compiler
would be quite small since for most value returning functions the
compiler could determine that it is impossible to fall off the end.
Michael M Rubenstein
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Martin D Kealey <martin@kcbbs.gen.nz>
Date: 1997/05/08 Raw View
>|>: [stmt.return]:
>|>: a) Flowing off the end of a value-returning function should not produce
>|>: undefined behavior -- it should make the program ill-formed. This is
>|>: certainly always detectable at compile time.
In article <rf5iv0y9xaj.fsf@vx.cit.alcatel.fr> James Kanze wrote:
> I don't think so. Despite the assertion of the original poster,
> detecting flowing off the end of a value-returning function is
> equivalent to the halting problem, and thus nor solvable in finite time.
> So I don't think we want this.
(I concur.)
[Discussion about calling "terminate" as a "free" run-time check in
place of undefined behaviour when a non-trivial constructor would be
involved in the return mechanism.
Remember that undefined behaviour can be an avenue for the optimiser;
any code which appears only in the flow graph before falling off the
end cannot be passed through without invoking undefined behaviour, and
therefore the compiler should be free not to generate the code at
all. For example, it could change
int foo( int x ) {
for ( int y = 0 ; y < x ; y++ )
if ( g(y) != 0 )
return x;
}
into
int foo( int x ) {
for ( int y = 0 ; g(y) == 0 ; y++ ) {}
return x;
}
where the test "y<x" can be entirely dispensed with, since it cannot
materially affect the result. In general, there are possibilities for
pruning the branch tree based on an implied promise of "unreachable
code".
Also, the last function call immediately before the end of a function
could reasonably be assumed to be non-returning (like exit or abort)
and therefore the code generator could avoid outputting any clean-up
code, since it "won't be reached".
-Martin.
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Alexandre Oliva <oliva@dcc.unicamp.br>
Date: 1997/05/08 Raw View
Mike Rubenstein writes:
> Alexandre Oliva <oliva@dcc.unicamp.br> wrote:
>> I'd create a standard exception such as std::no_return_exception and
>> get the compiler implicitly generate:
>> throw std::no_return_exception(__FILE__, __LINE__);
> I think the standard exception idea has merit. While it would break
> some now legal code, I don't think this would be a great burden.
How would it break legal code? It would only be inserted in functions
that might fall off the end, and this is illegal code.
--
Alexandre Oliva
mailto:oliva@dcc.unicamp.br mailto:aoliva@acm.org
Universidade Estadual de Campinas, SP, Brasil
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: phalpern@truffle.ma.ultranet.com (Pablo Halpern)
Date: 1997/05/08 Raw View
"Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com> wrote:
>In this case, I would expect the compiler to analyze it from the point
>of view of that i could be any int, and issue an error or warning. It
>would be up to me to quiet this error by putting in a default case.
The point is that the above is a valid program and has been a valid
program for a long time. Calling the above ill-formed and allowing the
compiler to refuse to compile it would break perfectly good, bug-free
programs. The compiler is always *permitted* to issue a warning for
things like that, but the standard never *requires* a diagnostic to be
issued except for ill-formed code.
The compiler can issue a warning for bad indent style or misspelled
comments, for all I care, so long as it compiles all valid programs.
Whether the compiler generates a warning for potentially dangerous
constructs should be a quality-of-implementation issue, not a standards
issue.
-------------------------------------------------------------
Pablo Halpern phalpern@truffle.ultranet.com
I am self-employed. Therefore, my opinions *do* represent
those of my employer.
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: videoman@tiac.net (Videoman)
Date: 1997/05/09 Raw View
On 06 May 1997 12:57:11 PDT, James Kuyper <kuyper@wizard.net> wrote:
>C/C++ is very careful to declare the return type of a function, and even
>to declare that a function doesn't return any type at all. I seems to me
>a very logical extension to allow a function to be declared 'noreturn'.
>It would allow more accurate flow analysis by compilers and code
>checkers, which in turn might allow a few extra optimizations. A
>function declared 'noreturn' would produce an (error ? warning) message
>if it terminates by any method except calling another function declared
>'noreturn'. abort() and exit() would, of course, be labeled 'noreturn'.
>I don't understand exceptions well enough yet to be sure about throw().
>Either it should be declared 'noreturn', or terminating a 'noreturn'
>function by throwing an exception should also be permitted.
>'noreturn' would be a promise, like 'const'; if a function cannot
>guarantee that it won't return, it shouldn't be declared 'noreturn'.
May I suggest something here? I have been thinking of something
similar for quite some time - user attribute tags. (This is an
expression of the general concept of objects/attributes and
association, applied to the C/C++ programming domain.)
Try this for a syntax:
typetag "tag value" tagname;
or perhaps just
typetag tagname;
Perhaps one could aggregate type tags this way:
typetag foo1..n bar;
typetag bar would represent the group of typetags foo1...n
These user-defined attribute tags could be applied to nearly anything,
and would have the effect of modifying the type signature.
There would be a myriad of uses. For example, they could be used to
fix those very annying off-by-one problems.
typetag based_1;
typetag based_0;
template<class T>
based_1 int operator int(based_0 int i)
{
return i+1;
}
template<class T>
based_0 int operator int(based_1 int i)
{
return i-1;
}
These template functions would allow the automatic adjustment of
objects passed as arguments to functions requiring 0-based or 1-based
values and tagged as such.
Tags could also be used to represent attributes of member functions
with regards to ownership, without requiring the user to mangle the
name of the method itself.
typetag receives_ownership;
typetag gives_ownership;
etc, ...
You might be wondering, why not just use a typedef or a class?
The problem with that is, an abstract type is only a single entity.
User tags could be used in a mix-and-match fashion, which would
require an exponential (polynomial?) number of abstract types to
represent the same set of possiblities with user tags.
In a way, type tags represent another aspect of meta-programming, that
of associating compile-time attributes with objects. They would also
support aggregation, which could be used as well for a crude type of
derivation.
In the particular case quoted above, however, noreturn would have to
be system-defined, and have a special meaning, so perhaps it should
have the status of a full keyword.
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Max TenEyck Woodbury <mtew@cds.duke.edu>
Date: 1997/05/09 Raw View
Gerard Weatherby wrote:
>
> Paul D. DeRocco wrote:
> -
> - Pablo Halpern wrote:
> - >
> - > int lookup(int i)
> - > {
> - > switch (i)
> - > {
> - > case 1: return -1;
> - > case 2: return 1;
> - > case 3: return 0;
> - > }
> - > }
> - >
> - > The compiler doesn't know if 1, 2 or 3 are the only possible values
> for
> - > i. Therefore, it cannot determine if it this function will ever
> flow off
> - > the end. In the limited cases where it *can* determine that the
> function
> - > will flow off the end, it is certainly allowed to issue a
> diagnostic.
> -
> - In this case, I would expect the compiler to analyze it from the point
> - of view of that i could be any int, and issue an error or warning. It
> - would be up to me to quiet this error by putting in a default case.
> -
> - --
> -
> - Ciao,
> - Paul
> ---
> So you add,
> case 3: return 0;
> default: return 0; /*this never really executes, but I had
> to put it in because the compiler requires it */
>
> or
> case 3: return 0;
> default:
> throw "bad value";
> return 0; /* obviously, this never really executes, but I had
> to put it in because the compiler requires it */
> ??
> IMO, having additional non-executing code to hush the compiler is a
> waste and detracts from the readability of the program. I'd rather see:
> case 3: return 0;
> default: asset(0);
> or
> case 3: return 0;
> default:
> throw "bad value";
> }
but the following also works and doesn't produce extra code or require
(too much) explination:
default: /* bad input case */
case 3: return 0;
mtew@cds.duke.edu
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1997/05/09 Raw View
Gerard Weatherby wrote:
>
> Paul D. DeRocco wrote:
> -
> - Pablo Halpern wrote:
> - >
> - > int lookup(int i)
> - > {
> - > switch (i)
> - > {
> - > case 1: return -1;
> - > case 2: return 1;
> - > case 3: return 0;
> - > }
> - > }
> - >
> - > The compiler doesn't know if 1, 2 or 3 are the only possible values
> for
> - > i. Therefore, it cannot determine if it this function will ever
> flow off
> - > the end. In the limited cases where it *can* determine that the
> function
> - > will flow off the end, it is certainly allowed to issue a
> diagnostic.
> -
> - In this case, I would expect the compiler to analyze it from the point
> - of view of that i could be any int, and issue an error or warning. It
> - would be up to me to quiet this error by putting in a default case.
> -
> - --
> -
> - Ciao,
> - Paul
> ---
> So you add,
> case 3: return 0;
> default: return 0; /*this never really executes, but I had
> to put it in because the compiler requires it */
>
> or
> case 3: return 0;
> default:
> throw "bad value";
> return 0; /* obviously, this never really executes, but I had
> to put it in because the compiler requires it */
> ??
> IMO, having additional non-executing code to hush the compiler is a
> waste and detracts from the readability of the program. I'd rather see:
> case 3: return 0;
> default: asset(0);
> or
> case 3: return 0;
> default:
> throw "bad value";
> }
what about:
int lookup(int i)
{
switch(i)
{
case 1: return -1;
case 2: return 1;
default: return 0;
}
}
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1997/05/09 Raw View
James Kuyper wrote:
[...]
> C/C++ is very careful to declare the return type of a function, and even
> to declare that a function doesn't return any type at all. I seems to me
> a very logical extension to allow a function to be declared 'noreturn'.
> It would allow more accurate flow analysis by compilers and code
> checkers, which in turn might allow a few extra optimizations. A
> function declared 'noreturn' would produce an (error ? warning) message
> if it terminates by any method except calling another function declared
> 'noreturn'. abort() and exit() would, of course, be labeled 'noreturn'.
I'd also like this addition.
> I don't understand exceptions well enough yet to be sure about throw().
> Either it should be declared 'noreturn', or terminating a 'noreturn'
> function by throwing an exception should also be permitted.
> 'noreturn' would be a promise, like 'const'; if a function cannot
> guarantee that it won't return, it shouldn't be declared 'noreturn'.
>
Here, I disagree: A function that is declared noreturn should *not*
return,
not even via exception. Look f. ex. at the following code:
noreturn fatal()
{
throw "Hey, I return anyway - tricky, isn't it?";
}
class X
{
public:
X();
~X();
void do_something()
{
if (some_condition_which_might_be_very_dangerous())
fatal(); // we better stop immediatly, every operation now is
dangerous!
// ... (whatever should be done)
}
}
void f()
{
X x;
create_fatal_condition(x);
x.do_something(); // will call fatal(), which returns - in spite of
noreturn -
// with an exception
} // Here x is destroyed - because of fatal condition, this is
dangerous...
The better way to handle noreturn would be to add an implicit throw()
specification if none is given.
> I don't think this suggestion would break existing code. A function that
> was in fact 'noreturn' but not declared as such would still be valid.
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: cwaters@Systems.DHL.COM (Chris Waters)
Date: 1997/05/09 Raw View
In article <oru3kdvcvg.fsf@sunsite.dcc.unicamp.br>
Alexandre Oliva <oliva@dcc.unicamp.br> writes:
>Mike Rubenstein writes:
>> Alexandre Oliva <oliva@dcc.unicamp.br> wrote:
>>> I'd create a standard exception such as std::no_return_exception and
>>> get the compiler implicitly generate:
>>> throw std::no_return_exception(__FILE__, __LINE__);
>> I think the standard exception idea has merit. While it would break
>> some now legal code, I don't think this would be a great burden.
>How would it break legal code? It would only be inserted in functions
>that might fall off the end, and this is illegal code.
Falling off the end produces undefined behavior, which may or may not
be considered "legal", depending on how you look at it. Certainly
it's possible that for a given compiler and platform the behavior
could be well-defined, even if the standard remains silent on the
subject. Although anyone who relies on such hackery probably deserves
to have their code break.
But whether it breaks any code, legal or not, I think this idea
*would* be a burden, and in some cases, a great and undue burden.
We're talking about inserting code that should never be executed if
the rest of the code actually works properly. If a function that
might (but in practice does not) walk off the end is, e.g. an inline
function, the amount of code which is inserted-but-never-executed
could be quite large.
As an option, say for debugging, this might be nice - very nice indeed
- but I think it would be a mistake for the standard to *require* an
exception. Note that the current behavior is undefined, so a given
compiler is already free to insert an exception *if it wants*. The job
of the standard is not to penalize experts in order to protect novices
and the careless. Call it a quality of implementation issue, talk to
your compiler vendor, or whatever.
In a language which supports arbitrary casts, wild pointers, and all
the memory leaks you could ask for, this falling-off-the-end-of-a-
function issue seems like pretty small potatoes in any case, though I
admit that that's not an excuse.
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: "Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com>
Date: 1997/05/10 Raw View
James Kuyper wrote:
> C/C++ is very careful to declare the return type of a function, and even
> to declare that a function doesn't return any type at all. I seems to me
> a very logical extension to allow a function to be declared 'noreturn'.
> It would allow more accurate flow analysis by compilers and code
> checkers, which in turn might allow a few extra optimizations. A
> function declared 'noreturn' would produce an (error ? warning) message
> if it terminates by any method except calling another function declared
> 'noreturn'. abort() and exit() would, of course, be labeled 'noreturn'.
> I don't understand exceptions well enough yet to be sure about throw().
> Either it should be declared 'noreturn', or terminating a 'noreturn'
> function by throwing an exception should also be permitted.
> 'noreturn' would be a promise, like 'const'; if a function cannot
> guarantee that it won't return, it shouldn't be declared 'noreturn'.
This is sometimes done with a #pragma. I think it's best done with a
#pragma, since it is merely an optimization hint, and not something that
affects the meaning of the program.
--
Ciao,
Paul
(Please remove the "strip_these_words_" prefix from the return
address, which has been altered to foil junk mail senders.)
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: miker3@ix.netcom.com (Mike Rubenstein)
Date: 1997/05/12 Raw View
d96-mst@nada.kth.se (Mikael Steldal) wrote:
> In article <336e56ed.13312993@nntp.ix.netcom.com>,
> miker3@ix.netcom.com (Mike Rubenstein) wrote:
>
> >How can the compiler tell? for example if is defined as
> >
> > int g(i) { return 1; }
> >
> >then it is impossible for the compiler to determine that f(int) cannot
> >fall off the end unless it sees the definition of g(int).
>
> Sorry, I don't understand this example at all. How is f() and g() related?
Perhaps if you hadn't cut the example I was refering to, you would
understand:
> >int f(int i)
> >{
> > for( int j = 0; j < 128; ++j ) {
> > i = g(i);
> > if( abs(i) < 2 ) return j;
> > }
> >}
> >
> >Can function f exit by falling off the end? The compiler
cannot tell.
>
> But the compiler CAN tell that it's possible for the
function to fall off
> the end. The standard can specify that that possibility is
disallowed. Only
> simple flow-analysis would be nessesary.
>
> >Another problem. Consider the code
> >
> > int f(int i)
> > {
> > switch (abs(i) % 5)
> > {
> > case 0:
> > case 1:
> > return 7;
> >
> > case 2:
> > case 3:
> > return 12;
> >
> > case 4:
> > return 2;
> > }
> > }
> >
> >Do we require the compiler analyze the matematics to determine that
> >these are the only possible cases?
>
> No. All such switch statements must have a default clause.
I can't find that in the draft -- could you please give me a
reference.
Why should I be required to put in an unnecessary default: label? The
example I gave cannot fall off the end.
But even if that won't help. Let's rewrite my example:
void handle_impossible_error();
int f(int i)
{
switch (abs(i) % 5)
{
case 0:
case 1:
return 7;
case 2:
case 3:
return 12;
case 4:
return 2;
default:
handle_impossible_error();
}
}
In another compiliation unit I have
void handle_impossible_error()
{
// put error message to log file or something
throw "impossible_error";
}
Michael M Rubenstein
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Martin D Kealey <martin@kcbbs.gen.nz>
Date: 1997/05/12 Raw View
In article <3374E831.7A3A@pratique.fr> you wrote:
> A program should be well-formed or not in itself, this shouldn't
> depend on some optimisation level/compiler switch/the choice of
> compiler; this is nearly (not absolutly) the case today.
> So the compiler can issue a warning but not an error:
> int i = 0;
> const int ci = 0;
> int j = 1/i; // a good compiler with optimisation on will issue
> // a warning but isn't allowed to issue an error
> int cj = 1/ci; // error here
In the case of the initialisation of j, such source code would inevitably
lead to undefined behaviour; is there anything that says the temporal scope
of that undefined behaviour doesn't reach back beyond the start of execution
and into the compilation phase, thus making refusal to compile legal?
[and later...]
> What about:
> switch (i)
> {
> case 1: return -1;
> case 2: return 0;
> case 3: return 1;
> no_default;
> }
We do have it, except that it's spelt more like
default: abort();
(or maybe default: assert(0);)
-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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: James Kuyper <kuyper@wizard.net>
Date: 1997/05/12 Raw View
Mikael Steldal wrote:
>
> In article <336e56ed.13312993@nntp.ix.netcom.com>,
> miker3@ix.netcom.com (Mike Rubenstein) wrote:
>
> >How can the compiler tell? for example if is defined as
> >
> > int g(i) { return 1; }
> >
> >then it is impossible for the compiler to determine that f(int) cannot
> >fall off the end unless it sees the definition of g(int).
>
> Sorry, I don't understand this example at all. How is f() and g() related?
Please review the definition of f() which was given in the message that
you are replying to. The functions are related because f() calls g().
f() can fall off the end, or not fall off the end, depending upon what
values g() returns. Since the definition of g() might reside in a
completely different module, and might even be written in a different
language, the compiler alone cannot in general determine whether f()
will fall off the end. The best the compiler can do is say that it might
do so, depending upon the values returned by g().
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Julian Pardoe <pardoej@lonnds.ml.com>
Date: 1997/05/12 Raw View
Paul D. DeRocco wrote:
>
> James Kuyper wrote:
>
> > C/C++ is very careful to declare the return type of a function, and even
> > to declare that a function doesn't return any type at all. I seems to me
> > a very logical extension to allow a function to be declared 'noreturn'.
I always wanted this in Algol 68C! On the other hand I haven't really
missed in in C/C++.
> > It would allow more accurate flow analysis by compilers and code
> > checkers, which in turn might allow a few extra optimizations. A
> > function declared 'noreturn' would produce an (error ? warning) message
> > if it terminates by any method except calling another function declared
> > 'noreturn'. abort() and exit() would, of course, be labeled 'noreturn'.
> > I don't understand exceptions well enough yet to be sure about throw().
> > Either it should be declared 'noreturn', or terminating a 'noreturn'
> > function by throwing an exception should also be permitted.
> > 'noreturn' would be a promise, like 'const'; if a function cannot
> > guarantee that it won't return, it shouldn't be declared 'noreturn'.
>
> This is sometimes done with a #pragma. I think it's best done with a
> #pragma, since it is merely an optimization hint, and not something that
> affects the meaning of the program.
Well, it does make a difference in that a noreturn function pointer can be
assigned to a function pointer variable regardless of the return type
specified by the variable.
Given
noreturn byebye (int a) { printf ("Bye bye!\n"); exit (1); }
I should be able to write
X (*f) (int) = byebye
regardless of the what type X is.
-- jP --
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/05/14 Raw View
cwaters@Systems.DHL.COM (Chris Waters) writes:
|> In article <oru3kdvcvg.fsf@sunsite.dcc.unicamp.br>
|> Alexandre Oliva <oliva@dcc.unicamp.br> writes:
|> >Mike Rubenstein writes:
|> >> Alexandre Oliva <oliva@dcc.unicamp.br> wrote:
|>
|> >>> I'd create a standard exception such as std::no_return_exception and
|> >>> get the compiler implicitly generate:
|>
|> >>> throw std::no_return_exception(__FILE__, __LINE__);
|>
|> >> I think the standard exception idea has merit. While it would break
|> >> some now legal code, I don't think this would be a great burden.
|>
|> >How would it break legal code? It would only be inserted in functions
|> >that might fall off the end, and this is illegal code.
|>
|> Falling off the end produces undefined behavior, which may or may not
|> be considered "legal", depending on how you look at it. Certainly
|> it's possible that for a given compiler and platform the behavior
|> could be well-defined, even if the standard remains silent on the
|> subject. Although anyone who relies on such hackery probably deserves
|> to have their code break.
I *think* that falling off the end of a function returning int (or an
integral type) is legal and well defined, as long as the caller doesn't
use the return value. (A ghost of C compatibility, so to speak, from
the times when there was no void, and functions returned an int unless
you said otherwise.)
|> But whether it breaks any code, legal or not, I think this idea
|> *would* be a burden, and in some cases, a great and undue burden.
|> We're talking about inserting code that should never be executed if
|> the rest of the code actually works properly. If a function that
|> might (but in practice does not) walk off the end is, e.g. an inline
|> function, the amount of code which is inserted-but-never-executed
|> could be quite large.
The amount of code generated is a single instruction: branch to the
error handling routine in the library. Not very much, IMHO. And the
compiler has to generate something (a return instruction, at the very
least).
|> As an option, say for debugging, this might be nice - very nice indeed
|> - but I think it would be a mistake for the standard to *require* an
|> exception. Note that the current behavior is undefined, so a given
|> compiler is already free to insert an exception *if it wants*. The job
|> of the standard is not to penalize experts in order to protect novices
|> and the careless. Call it a quality of implementation issue, talk to
|> your compiler vendor, or whatever.
Agreed. I'm perfectly happy to leave it as undefined behavior, if only
to allow the compiler to do things like test if the program is executing
in a IDE, and if so, kick off the debugger.
|> In a language which supports arbitrary casts, wild pointers, and all
|> the memory leaks you could ask for, this falling-off-the-end-of-a-
|> function issue seems like pretty small potatoes in any case, though I
|> admit that that's not an excuse.
I think the point is that the test costs nothing (in run-time, at
least), so it would be stupid not to implement it. On the other hand,
garbage collection would eliminate a significant number of memory
management problems, at little or no measurable run-time cost for most
applications, and yet I'm not aware of a compiler which supports it.
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Julian Pardoe <pardoej@lonnds.ml.com>
Date: 1997/05/14 Raw View
David Chase wrote:
>
> > Bernard Badger wrote:
> > > If C++ completes the definitions of /, %, << and >> by supplying
> > > requirements to the undefined parts, then it isn't, technically,
> > > incompatible with C.
>
> This problems (the implementation-definedness of / and %) has annoyed
> me for years. The basic cost of hardware division/remainder (not to
> be confused with division and remainder in the source code, pre-
> optimization) is high enough, and the relative frequency is low enough,
> that it will not make a difference to anyone (except perhaps certain
> well-known comp.arch curmudgeons) if it costs an extra cycle or two to get
> division and remainder "right".
Well, some might disagree as to what "right" means.
But my question is: Why bother? I have rarely ever used integer / and %
with negative numbers and have had little cause to care what their
behaviour is. When it has mattered I have wrapped the operation is a
small and well commented function.
(I wonder: Wouldn't the definition of standard ways of determining
whether chars are signed or unsigned, whether signed >> zero-extends
or sign-extends and what / and % do make life a lot easier -- at least
for those of use who don't mind the occasional #if?)
-- jP --
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/05/14 Raw View
Martin D Kealey <martin@kcbbs.gen.nz> writes:
> In article <3374E831.7A3A@pratique.fr> you wrote:
> > int i = 0;
> > int j = 1/i; // a good compiler with optimisation on will issue
> > // a warning but isn't allowed to issue an error
> In the case of the initialisation of j, such source code would inevitably
> lead to undefined behaviour; is there anything that says the temporal scope
> of that undefined behaviour doesn't reach back beyond the start of execution
> and into the compilation phase, thus making refusal to compile legal?
Undefined baviour can be executed out-of-order, before well defined
behaviour, but only if the statement is executed.
> [and later...]
> > What about:
>
> > switch (i)
> > {
> > case 1: return -1;
> > case 2: return 0;
> > case 3: return 1;
> > no_default;
> > }
>
> We do have it, except that it's spelt more like
>
> default: abort();
no_default isn't something I'd like see in the language,
it's just an idea from the top of my head.
The semantic of no_default would be 'undefined behaviour',
not abort; it would only be checked in debug mode.
--
Valentin Bonnard
mailto:bonnardv@pratique.fr
http://www.pratique.fr/~bonnardv (Informations sur le C++ en Francais)
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: miker3@ix.netcom.com (Mike Rubenstein)
Date: 1997/05/14 Raw View
James Kanze <james-albert.kanze@vx.cit.alcatel.fr> wrote:
> I *think* that falling off the end of a function returning int (or an
> integral type) is legal and well defined, as long as the caller doesn't
> use the return value. (A ghost of C compatibility, so to speak, from
> the times when there was no void, and functions returned an int unless
> you said otherwise.)
That's what I thought, but the draft says (6.3)
Flowing off the end of a function is equivalent to a return
with no value; this results in undefined behavior in a
value-returning function.
Michael M Rubenstein
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Steve Clamage <stephen.clamage@eng.sun.com>
Date: 1997/05/14 Raw View
James Kanze wrote:
> |>
> |> Falling off the end produces undefined behavior, which may or may n=
ot
> |> be considered "legal", depending on how you look at it. Certainly
> |> it's possible that for a given compiler and platform the behavior
> |> could be well-defined, even if the standard remains silent on the
> |> subject. Although anyone who relies on such hackery probably deser=
ves
> |> to have their code break.
>=20
> I *think* that falling off the end of a function returning int (or an
> integral type) is legal and well defined, as long as the caller doesn't
> use the return value. =20
That is the case in C -- undefined only if the caller uses the
value that is supposed to be returned. C++ is stricter.
Author: James Kuyper <kuyper@wizard.net>
Date: 1997/05/06 Raw View
Tony Cook wrote:
>
> John David Galt (jdg@rahul.net) wrote:
...
> : * The prefix 'bit', which distinguishes _some_ bitwise operations from
> : their logical counterparts (example: 'bitand' vs. 'and'), is not used
> : consistently. Let's either apply it to ALL bitwise operations (making them
> : bitcompl, bitnot, bitxor, bitand_assign, bitor_assign, and bitxor_assign), or
> : eliminate it and put a 'bool' or 'log' prefix on the two logical operations.
>
> Only 'and' and 'or' have logical and bitwise variants.
Not quite true: ~ and ! are bitwise and logical versions of the same
operator; ^ and != are bitwise and logical versions of the same
operator. However, I agree that the current names are reasonable, and
should not be changed.
Note: ! and != function as the logical equivalents of complement and xor
only when applied to boolean values. They fail some of the required
identities when applied to arbitrary values. (example: a == ~~a, but for
any value of 'a' other than 'true' or 'false', a != !!a).
...
> : [stmt.iter]:
> : The syntax of "for" appears to require that for-init-statement be non-empty.
^^^^^^^^^^^^^^^^^^
> : I assume this is a mistake rather than an intended change. Please clarify.
>
> The expression in an expression statement is optional.
^^^^^^^^^^
This doesn't answer the question. The answer is that the
for-init-statment is not optional, but can consist of a single ';',
which is probably what John Galt was thinking of as 'empty'.
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Steve Clamage <stephen.clamage@eng.sun.com>
Date: 1997/05/06 Raw View
Lars Farm wrote:
>
> Steve Clamage <stephen.clamage@eng.sun.com> wrote:
>
> > If the C++ standard places requirements on arithmetic that the C
> > standard does not, we will certainly create circumstances where a C++
> > compiler cannot be both standard-conforming and compatible with C.
> > Such a situation benefits no one.
> >
> > The C committee may elect to place tighter restrictions on arithmetic.
> > Any C++ compiler which wishes to be compatible with a C compiler
> > following the new C rules will in turn follow those rules. Again, the
> > C++ standard should not make that impossible. The next round of the C++
> > standard would then adopt the new C rules.
>
> Doesn't this argument work both ways? "The C++ committee may elect to
> place tighter restrictions on arithmetic. Any C compiler which wishes to
> be compatible with a C++ compiler following the new C++ rules will in
> turn follow those rules." It would still be a standard C compiler
> wouldn't it?
*In principle* the argument could work both ways.
The reality is that a primary design goal of C++ is compatibility with
C. C is considered the base language, inherited by C++. As a
consequence,
you can migrate programs or program fragments easily from C to C++.
If you drop that design goal, why stop (or even start) with changing the
semantics of division? I have a little list ...
---
Steve Clamage, stephen.clamage@eng.sun.com
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: James Kuyper <kuyper@wizard.net>
Date: 1997/05/06 Raw View
Barry Margolin wrote:
...
> But suppose the code were:
>
> if (i < 0)
> my_error_function("i is negative!");
> else
> return i + 1;
>
> where my_error_function() always calls abort() or exit(). Wrappers for
> exit() and abort() are quite common (I strongly recommend them), but
> there's no way for the compiler to know that these functions never return.
> If it were really desirable to allow the compiler to refuse to compile
> functions that look like they could fall off the end of a function, we'd
> need an enhancement to function prototypes to allow you to declare
> functions that don't return. However, we'd still have a problem with a
> function like:
>
> void another_error_function(char *message, bool should_exit)
>
> This function returns if should_exit is false, but doesn't return if it's
> true.
...
C/C++ is very careful to declare the return type of a function, and even
to declare that a function doesn't return any type at all. I seems to me
a very logical extension to allow a function to be declared 'noreturn'.
It would allow more accurate flow analysis by compilers and code
checkers, which in turn might allow a few extra optimizations. A
function declared 'noreturn' would produce an (error ? warning) message
if it terminates by any method except calling another function declared
'noreturn'. abort() and exit() would, of course, be labeled 'noreturn'.
I don't understand exceptions well enough yet to be sure about throw().
Either it should be declared 'noreturn', or terminating a 'noreturn'
function by throwing an exception should also be permitted.
'noreturn' would be a promise, like 'const'; if a function cannot
guarantee that it won't return, it shouldn't be declared 'noreturn'.
I don't think this suggestion would break existing code. A function that
was in fact 'noreturn' but not declared as such would still be valid.
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/05/06 Raw View
James Kanze <james-albert.kanze@vx.cit.alcatel.fr> writes:
>According to the draft, at least one of the parameters of a
>user defined operator must be either a class type or an enum, or a
>reference to a class type or an enum. (I wonder: are unions legal?
>They probably should be, although it's hardly an important point.)
Yes, they are. Structs, unions, and classes are all "class types".
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Alexandre Oliva <oliva@dcc.unicamp.br>
Date: 1997/05/07 Raw View
Mike Rubenstein wrote:
> then it is impossible for the compiler to determine that f(int) cannot
> fall off the end unless it sees the definition of g(int).
> How do you word the requirement to avoid this problem?
I'd create a standard exception such as std::no_return_exception and
get the compiler implicitly generate:
throw std::no_return_exception(__FILE__, __LINE__);
or
abort();
wherever it might be possible for a non-void function to fall off the
end.
--
Alexandre Oliva
mailto:oliva@dcc.unicamp.br mailto:aoliva@acm.org
Universidade Estadual de Campinas, SP, Brasil
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Gerard Weatherby <gerardw@alum.mit.edu>
Date: 1997/05/07 Raw View
Paul D. DeRocco wrote:
-
- Pablo Halpern wrote:
- >
- > int lookup(int i)
- > {
- > switch (i)
- > {
- > case 1: return -1;
- > case 2: return 1;
- > case 3: return 0;
- > }
- > }
- >
- > The compiler doesn't know if 1, 2 or 3 are the only possible values
for
- > i. Therefore, it cannot determine if it this function will ever
flow off
- > the end. In the limited cases where it *can* determine that the
function
- > will flow off the end, it is certainly allowed to issue a
diagnostic.
-
- In this case, I would expect the compiler to analyze it from the point
- of view of that i could be any int, and issue an error or warning. It
- would be up to me to quiet this error by putting in a default case.
-
- --
-
- Ciao,
- Paul
---
So you add,
case 3: return 0;
default: return 0; /*this never really executes, but I had
to put it in because the compiler requires it */
or
case 3: return 0;
default:
throw "bad value";
return 0; /* obviously, this never really executes, but I had
to put it in because the compiler requires it */
??
IMO, having additional non-executing code to hush the compiler is a
waste and detracts from the readability of the program. I'd rather see:
case 3: return 0;
default: asset(0);
or
case 3: return 0;
default:
throw "bad value";
}
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: d96-mst@nada.kth.se (Mikael Steldal)
Date: 1997/05/05 Raw View
In article <336774A1.73E1@Eng.Sun.COM>,
Steve Clamage <stephen.clamage@Eng.Sun.COM> wrote:
>int f(int i)
>{
> for( int j = 0; j < 128; ++j ) {
> i = g(i);
> if( abs(i) < 2 ) return j;
> }
>}
>
>Can function f exit by falling off the end? The compiler cannot tell.
But the compiler CAN tell that it's possible for the function to fall off
the end. The standard can specify that that possibility is disallowed. Only
simple flow-analysis would be nessesary.
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com>
Date: 1997/05/05 Raw View
David Chase wrote:
>
> This problems (the implementation-definedness of / and %) has annoyed
> me for years. The basic cost of hardware division/remainder (not to
> be confused with division and remainder in the source code, pre-
> optimization) is high enough, and the relative frequency is low enough,
> that it will not make a difference to anyone (except perhaps certain
> well-known comp.arch curmudgeons) if it costs an extra cycle or two to get
> division and remainder "right".
It's more than an extra cycle or two, if your machine does quotient and
remainder and what you really want is div and mod, or vice versa.
> But this is already true, since you could have two C compilers on the
> same platform which used different choices for % and /. The reason
> you don't worry about this (and I agree, it is not a problem, except
> for a standards weenie) is because nobody does that, and most C compilers
> agree anyway. At least, I think that they agree; everywhere that I've
> looked, they seem to follow the Fortran rule:
>
> x/y is the integer closest to the mathematical quotient and
> between zero and the mathematical quotient inclusively. E.g.,
> (-8)/3 = -2.
>
> If, in practice, most C compilers follow this rule, why not adopt it,
> and make life easier for C++ programmers? No PORTABLE C program can
> rely on these operators having a consistent definition, anyway, so
> little has been lost.
Most C/C++ implementations follow this rule because that's how the DIV
instruction on the CPU happens to be implemented. That's why two
compilers for the same machine will almost certainly work the same way.
The only time this is an actual issue is when the operands are negative.
However, C/C++ steers programmers into using signed types even in
situations where the values are never negative (e.g., for (int i=0; i<n;
i++)...). To require that the compiler for a machine that happens not to
have the appropriate kind of DIV instruction to meet the Fortran rule
spit out the extra instructions necessary to resolve this
incompatibility, even in cases where the programmer knows that it
doesn't matter, might be more irritating that it's worth.
The real solution, in my view, is for the standard to define unambiguous
functions, such as div and mod, and quo and rem, and then specify that /
and % may be implemented as either the former pair or the latter pair.
This would allow the programmer to obtain the proper result when dealing
with negative numbers, but allow the compiler to do it either way when
dealing with positive numbers.
--
Ciao,
Paul
(Please send e-mail to mailto:pderocco@ix.netcom.com instead of the
return address, which has been altered to foil junk mail senders.)
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Steve Clamage <stephen.clamage@eng.sun.com>
Date: 1997/05/05 Raw View
David Chase wrote:
> Steve Clamage wrote:
> > It might force C and C++ implementations on the same platform to be
> > incompatible, which is what I really meant. The C compiler is allowed
> > to pick a definition for the sign of the remainder operator that is
> > most efficient, or most compatible with other software on the
> > platform. Since languages and platforms differ in that regard, any
> > more-explicit rule we mandate for C++ will be incompatible with some C
> > compilers on some platforms.
>
> But this is already true, since you could have two C compilers on the
> same platform which used different choices for % and /. ...
>
> > The term "C compatibility" as used in the C++ Committee is understood
> > to include the idea that a program valid in both C and C++ has the
> > same meaning in both languages.
>
> In this case, you are relying on an implementation-defined choice;
> this means that though it *could* have the same meaning, it need not
> have the same meaning.
It seems that either this point is difficult to grasp, or I just don't
explain it very well. I'll make yet another attempt.
We don't want to make it impossible for a C++ compiler to be compatible
with a C compiler on the same platform. Yes, a given platform may have
two or more incompatible C compilers, but the market will insist that a
given C++ compiler be compatible with at least one of them.
If the C++ standard places requirements on arithmetic that the C
standard does not, we will certainly create circumstances where a C++
compiler cannot be both standard-conforming and compatible with C.
Such a situation benefits no one.
The C committee may elect to place tighter restrictions on arithmetic.
Any C++ compiler which wishes to be compatible with a C compiler
following the new C rules will in turn follow those rules. Again, the
C++ standard should not make that impossible. The next round of the C++
standard would then adopt the new C rules.
---
Steve Clamage, stephen.clamage@eng.sun.com
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: miker3@ix.netcom.com (Mike Rubenstein)
Date: 1997/05/05 Raw View
d96-mst@nada.kth.se (Mikael Steldal) wrote:
>
> In article <336774A1.73E1@Eng.Sun.COM>,
> Steve Clamage <stephen.clamage@Eng.Sun.COM> wrote:
>
> >int f(int i)
> >{
> > for( int j = 0; j < 128; ++j ) {
> > i = g(i);
> > if( abs(i) < 2 ) return j;
> > }
> >}
> >
> >Can function f exit by falling off the end? The compiler cannot tell.
>
> But the compiler CAN tell that it's possible for the function to fall off
> the end. The standard can specify that that possibility is disallowed. Only
> simple flow-analysis would be nessesary.
How can the compiler tell? for example if is defined as
int g(i) { return 1; }
then it is impossible for the compiler to determine that f(int) cannot
fall off the end unless it sees the definition of g(int).
How do you word the requirement to avoid this problem?
Another problem. Consider the code
int f(int i)
{
switch (abs(i) % 5)
{
case 0:
case 1:
return 7;
case 2:
case 3:
return 12;
case 4:
return 2;
}
}
Do we require the compiler analyze the matematics to determine that
these are the only possible cases?
Or
int f(int i)
{
switch ((i * i) % 5)
{
case 0:
return 1;
case 1:
return 0;
case 4:
return 2;
}
}
Michael M Rubenstein
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/05/05 Raw View
"Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com> writes:
|> John David Galt wrote:
|> >
|> > [expr.mul]:
|> > Leaving the results of / and % (that is, the sign of the remainder)
|> > undefined for negative operands is a dumb idea, because it makes it difficult
|> > to write portable code. I realize that this was a hot political topic, but
|> > any choice would be preferable to copping out. I suggest this definition:
|> > (Given P > 0) X % P >= 0; X % (-P) <= 0.
|> > If this is left undefined, at least please add library functions that _are_
|> > predictable. I suggest:
|> > int pmod(int x, int y) is always >= 0;
|> > int smod(int x, int y) has the same sign as y;
|> > int pdiv(int x, int y) division with remainder = pmod(x,y)
|> > int sdiv(int x, int y) division with remainder = smod(x,y)
|>
|> I agree with this suggestion.
It is, in fact, already part of the standard, inherited from the C
standard. The function is called div (or ldiv for longs).
There is a problem with it. Although easily optimized (at least on my
HP, where / and % give exactly the same results), most compilers don't
bother, probably because the function is so little used. On the other
hand, maybe it is so little used because it does result in a function
call, rather than being optimized. To be truthful, on such platforms,
I would have expected to see it implemented as a macro:
#define div( n , d ) __builtin_div( n , d )
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/05/05 Raw View
tony@online.tmx.com.au (Tony Cook) writes:
[...]
|> : [expr]
|> : * "Operator overloading shall not modify the rules for the built-in
|> : operators, that is, for operators applied to types for which they are defined
|> : by the language itself." (5.3) Does this mean that I _can_ define:
|> : float operator % (float, float)
|> : since it is not defined by the language? I'm for it!
|>
|> neat! <grin>
But illegal. According to the draft, at least one of the parameters of a
user defined operator must be either a class type or an enum, or a
reference to a class type or an enum. (I wonder: are unions legal?
They probably should be, although it's hardly an important point.)
[...]
|> : [stmt.return]:
|> : a) Flowing off the end of a value-returning function should not produce
|> : undefined behavior -- it should make the program ill-formed. This is
|> : certainly always detectable at compile time.
|>
|> This is the case in the latest draft
I don't think so. Despite the assertion of the original poster,
detecting flowing off the end of a value-returning function is
equivalent to the halting problem, and thus nor solvable in finite time.
So I don't think we want this.
For historical reasons (and C compatibility), it is probably necessary
to support flowing off the end of a function returning int. This is
defined and well behaved, as long as the caller doesn't use the return
value. Although I think it very poor style, given the full history of C
and C++, I really don't think that we should change it.
It would certainly be possible to define a run-time behavior (say, call
terminate, or some such) if the return type has a non-trivial
constructor, rather than leave it undefined. I think, however, that
this would be the only case of run-time checking required in C++. While
the check is "free" (no run-time overhead), I'm not convinced that it is
worth mandating. Good implementation WILL do something along these
lines, much as they do for calling a pure virtual function.
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: phalpern@truffle.ma.ultranet.com (Pablo Halpern)
Date: 1997/05/05 Raw View
"Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com> wrote:
>Valentin Bonnard wrote:
>
>> > [stmt.return]:
>> > a) Flowing off the end of a value-returning function should not produce
>> > undefined behavior -- it should make the program ill-formed. This is
>> > certainly always detectable at compile time.
>>
>> It's absolutly impossible; only special cases can be detected.
>
>Hmmm. Can you give me an example of a situation where the compiler
>couldn't detect this? I can't think of one.
int lookup(int i)
{
switch (i)
{
case 1: return -1;
case 2: return 1;
case 3: return 0;
}
}
The compiler doesn't know if 1, 2 or 3 are the only possible values for
i. Therefore, it cannot determine if it this function will ever flow off
the end. In the limited cases where it *can* determine that the function
will flow off the end, it is certainly allowed to issue a diagnostic. Be
careful what you ask for, however, one version of the Microsoft compiler
I used refused to compile the following:
int f(int i)
{
if (i < 0)
throw invalid_arg();
else
return i + 1;
}
The compiler produced an *error* (not warning), saying that one branch
of execution did not result in a return statement being executed. Adding
an extra return statement to make the broken compiler happy caused a
non-broken compiler to issue a warning on the spurious return statement,
saying (correctly) that it was unreachable code.
-------------------------------------------------------------
Pablo Halpern phalpern@truffle.ultranet.com
I am self-employed. Therefore, my opinions *do* represent
those of my employer.
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: James Kuyper <kuyper@wizard.net>
Date: 1997/05/05 Raw View
Mike Rubenstein wrote:
>
> d96-mst@nada.kth.se (Mikael Steldal) wrote:
>
> >
> > In article <336774A1.73E1@Eng.Sun.COM>,
> > Steve Clamage <stephen.clamage@Eng.Sun.COM> wrote:
> >
> > >int f(int i)
> > >{
> > > for( int j = 0; j < 128; ++j ) {
> > > i = g(i);
> > > if( abs(i) < 2 ) return j;
> > > }
> > >}
> > >
> > >Can function f exit by falling off the end? The compiler cannot tell.
> >
> > But the compiler CAN tell that it's possible for the function to fall off
> > the end. The standard can specify that that possibility is disallowed. Only
> > simple flow-analysis would be nessesary.
>
> How can the compiler tell? for example if is defined as
>
> int g(i) { return 1; }
>
> then it is impossible for the compiler to determine that f(int) cannot
> fall off the end unless it sees the definition of g(int).
>
> How do you word the requirement to avoid this problem?
There are several related ways of dealing with this situation, you
merely need to choose one (I disagree with the basic idea, I'm merely
saying that it could be implemented). Instead of doing the exact
analysis that has been proven mathematically impossible, do a simpler,
less complete analysis that can be finished quickly, and interpret the
results conservatively. For instance, whether the function f() could
exit by falling off the end depends upon the definition of g(), which
might be in a completely different module; it might even have been
written in a different language. Therefore, f() could be consider
ill-formed if there is any definition of g() which would cause f() to
exit by falling off the end.
Similarly, it shouldn't be required (but should be allowed) for an
implementation to figure out that certain branches will never be
executed because of the specific values of various objects. A function
returning a value could be considered ill-formed if any path leads out
of the function without a return value, even though there are
difficult-to-analyze reasons why that path cannot be followed.
I dislike this idea, because it would force a lot of pointless code to
be added, in order to cover cases that cannot actually come up. It would
therefore require a rewrite of a lot of legacy code which was not
originally written that way. Warning messages might be entirely
appropriate, and are allowed by the current standard, but failing to
compile a module for this reason would not be acceptable.
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: miker3@ix.netcom.com (Mike Rubenstein)
Date: 1997/05/05 Raw View
James Kuyper <kuyper@wizard.net> wrote:
> Mike Rubenstein wrote:
> >
> > d96-mst@nada.kth.se (Mikael Steldal) wrote:
> >
> > >
> > > In article <336774A1.73E1@Eng.Sun.COM>,
> > > Steve Clamage <stephen.clamage@Eng.Sun.COM> wrote:
> > >
> > > >int f(int i)
> > > >{
> > > > for( int j = 0; j < 128; ++j ) {
> > > > i = g(i);
> > > > if( abs(i) < 2 ) return j;
> > > > }
> > > >}
> > > >
> > > >Can function f exit by falling off the end? The compiler cannot tell.
> > >
> > > But the compiler CAN tell that it's possible for the function to fall off
> > > the end. The standard can specify that that possibility is disallowed. Only
> > > simple flow-analysis would be nessesary.
> >
> > How can the compiler tell? for example if is defined as
> >
> > int g(i) { return 1; }
> >
> > then it is impossible for the compiler to determine that f(int) cannot
> > fall off the end unless it sees the definition of g(int).
> >
> > How do you word the requirement to avoid this problem?
>
> There are several related ways of dealing with this situation, you
> merely need to choose one (I disagree with the basic idea, I'm merely
> saying that it could be implemented). Instead of doing the exact
> analysis that has been proven mathematically impossible, do a simpler,
> less complete analysis that can be finished quickly, and interpret the
> results conservatively. For instance, whether the function f() could
> exit by falling off the end depends upon the definition of g(), which
> might be in a completely different module; it might even have been
> written in a different language. Therefore, f() could be consider
> ill-formed if there is any definition of g() which would cause f() to
> exit by falling off the end.
> Similarly, it shouldn't be required (but should be allowed) for an
> implementation to figure out that certain branches will never be
> executed because of the specific values of various objects. A function
> returning a value could be considered ill-formed if any path leads out
> of the function without a return value, even though there are
> difficult-to-analyze reasons why that path cannot be followed.
>
> I dislike this idea, because it would force a lot of pointless code to
> be added, in order to cover cases that cannot actually come up. It would
> therefore require a rewrite of a lot of legacy code which was not
> originally written that way. Warning messages might be entirely
> appropriate, and are allowed by the current standard, but failing to
> compile a module for this reason would not be acceptable.
Though it is theoretically impossible to do it in general, as you
point out one could do a simple, less complete analysis that is
adequate for many purposes. In fact, many compilers do such an
analysis and issue a warning and I believe such warnings are
desirable.
The problem isn't so much in doing the analysis as in specifying it in
a standard. Let's consider my second example
int f(int i)
{
switch ((i * i) % 5)
{
case 0:
return 1;
case 1:
return 0;
case 4:
return 2;
}
}
Does this require a diagnostic? If so, then a compiler that doesn't
issue a one is incorrect.
This doesn't seem very reasonable to me. After all, I can prove that
this code always returns a value (as long as i * i doesn't overflow,
but that results in undefined behavior anyways). Do we require a
diagnostic even though control can never fall off the end?
On the other hand, it seems equally unreasonable to require compilers
to do this analysis and not issue a diagnostic for this program but to
do so if the last case is 3.
Older versions of Microsoft VC++ did refuse to compile such code; it
was most annoying.
This isn't really a unique situation. At various times people have
suggested that a diagnostic be required for
int i;
// ...
i = i++;
Seems easy until you try to come up with wording that will require a
diagnostic in this case without requiring extremely difficult (or
impossible) analysis of the program to determine if the diagnostic is
required.
Michael M Rubenstein
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: "Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com>
Date: 1997/05/06 Raw View
Pablo Halpern wrote:
>
> int lookup(int i)
> {
> switch (i)
> {
> case 1: return -1;
> case 2: return 1;
> case 3: return 0;
> }
> }
>
> The compiler doesn't know if 1, 2 or 3 are the only possible values for
> i. Therefore, it cannot determine if it this function will ever flow off
> the end. In the limited cases where it *can* determine that the function
> will flow off the end, it is certainly allowed to issue a diagnostic.
In this case, I would expect the compiler to analyze it from the point
of view of that i could be any int, and issue an error or warning. It
would be up to me to quiet this error by putting in a default case.
--
Ciao,
Paul
(Please send e-mail to mailto:pderocco@ix.netcom.com instead of the
return address, which has been altered to foil junk mail senders.)
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Barry Margolin <barmar@bbnplanet.com>
Date: 1997/05/06 Raw View
In article <336e0cd4.10764256@news.ma.ultranet.com>,
Pablo Halpern <phalpern@truffle.ma.ultranet.com> wrote:
>int f(int i)
>{
> if (i < 0)
> throw invalid_arg();
> else
> return i + 1;
>}
>
>The compiler produced an *error* (not warning), saying that one branch
>of execution did not result in a return statement being executed. Adding
>an extra return statement to make the broken compiler happy caused a
>non-broken compiler to issue a warning on the spurious return statement,
>saying (correctly) that it was unreachable code.
This is probably closest to the problem. The problem with the above
example is that the compiler should know that execution never continues
after a throw, so this is clearly a bug in that compiler.
But suppose the code were:
if (i < 0)
my_error_function("i is negative!");
else
return i + 1;
where my_error_function() always calls abort() or exit(). Wrappers for
exit() and abort() are quite common (I strongly recommend them), but
there's no way for the compiler to know that these functions never return.
If it were really desirable to allow the compiler to refuse to compile
functions that look like they could fall off the end of a function, we'd
need an enhancement to function prototypes to allow you to declare
functions that don't return. However, we'd still have a problem with a
function like:
void another_error_function(char *message, bool should_exit)
This function returns if should_exit is false, but doesn't return if it's
true.
--
Barry Margolin
BBN Corporation, Cambridge, MA
barmar@bbnplanet.com
(BBN customers, call (800) 632-7638 option 1 for support)
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com>
Date: 1997/05/06 Raw View
James Kanze wrote:
> It is, in fact, already part of the standard, inherited from the C
> standard. The function is called div (or ldiv for longs).
But we need both. I think I recall some language (Algol, maybe, or Ada?)
that defined DIV and MOD for those situations where you wanted
truncation toward minus infinity, and QUO and REM for those situations
where you wanted truncation toward zero. And then / and % would be
defined as one or the other pair, for situations where the programmer
doesn't care (e.g., when the programmer knows that the operands are
actually never negative).
--
Ciao,
Paul
(Please send e-mail to mailto:pderocco@ix.netcom.com instead of the
return address, which has been altered to foil junk mail senders.)
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: lars.farm@ite.mh.se (Lars Farm)
Date: 1997/05/06 Raw View
Steve Clamage <stephen.clamage@eng.sun.com> wrote:
> If the C++ standard places requirements on arithmetic that the C
> standard does not, we will certainly create circumstances where a C++
> compiler cannot be both standard-conforming and compatible with C.
> Such a situation benefits no one.
>
> The C committee may elect to place tighter restrictions on arithmetic.
> Any C++ compiler which wishes to be compatible with a C compiler
> following the new C rules will in turn follow those rules. Again, the
> C++ standard should not make that impossible. The next round of the C++
> standard would then adopt the new C rules.
Doesn't this argument work both ways? "The C++ committee may elect to
place tighter restrictions on arithmetic. Any C compiler which wishes to
be compatible with a C++ compiler following the new C++ rules will in
turn follow those rules." It would still be a standard C compiler
wouldn't it?
--
Lars Farm; lars.farm@ite.mh.se - Limt/Channelmatic: lars.farm@limt.se
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/04/30 Raw View
Valentin Bonnard <bonnardv@pratique.fr> writes:
|> > [stmt.iter]:
|> > The syntax of "for" appears to require that for-init-statement be non-empty.
|> > I assume this is a mistake rather than an intended change. Please clarify.
|>
|> Certainly a bug !
Not at all. The syntax for "for" requires that the for-init-statement
be an expression-statement or a simple-declaration. An
expression-statement consists of an OPTIONAL expression, followed by a
semi-colon. In sum, what is commonly called an empty statement is in
fact a form of the expression-statement.
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com>
Date: 1997/04/30 Raw View
Valentin Bonnard wrote:
> > [stmt.jump]:
> > The [note] is, or ought to be, in error. Calling exit() should guarantee
> > destruction of all class objects with automatic duration. In existing
> > practice, that behavior (and the corresponding treatment of open files) is the
> > distinction between exit() and abort() (or on some systems, between exit() and
> > _exit()).
>
> I don't understand you point: calling exit() is like crashing; you can
> define an Exit_program exception and throw it to exit the porgram if
> you want to run dtors:
What's more, even if you do throw an exception, which ultimately
terminates the program where caught, that won't clean up properly in a
multi-threaded program.
> > [stmt.return]:
> > a) Flowing off the end of a value-returning function should not produce
> > undefined behavior -- it should make the program ill-formed. This is
> > certainly always detectable at compile time.
>
> It's absolutly impossible; only special cases can be detected.
Hmmm. Can you give me an example of a situation where the compiler
couldn't detect this? I can't think of one.
--
Ciao,
Paul
(Please send e-mail to mailto:pderocco@ix.netcom.com instead of the
return address, which has been altered to foil junk mail senders.)
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: James Kuyper <kuyper@wizard.net>
Date: 1997/04/30 Raw View
Valentin Bonnard wrote:
>
> John David Galt <jdg@rahul.net> writes:
...
> > [stmt.iter]:
> > The syntax of "for" appears to require that for-init-statement be non-empty.
correct.
> > I assume this is a mistake rather than an intended change. Please clarify.
It's not a mistake.
>
> Certainly a bug !
It isn't a bug.
6.5, paragraph 1 says:
...
for ( for-init-statement conditionopt ; expressionopt ) statement
for-init-statement:
expression-statement
simple-declaration
[Note: a for-init-statement ends with a semicolon. ]
The truth of the note follows from 6.2, paragraph 1:
expression-statement:
expressionopt ;
In particular, this means that for-init-statement can consist of as
little as as single character: ';'. This is probably what you were
thinking of as empty.
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/04/30 Raw View
Stephen.Clamage@eng.sun.com (Steve Clamage) writes:
|> > * If an expression violates rule 5.4 ("Between the previous and next
|> > sequence point a scalar object shall have its stored value modified at most
|> > once by the evaluation of an expression. Furthermore, the prior value shall
|> > be accessed only to determine the value to be stored."), and this can be
|> > determined from just that one statement and the declarations of the variables
|> > it uses, as in these examples, then the code should be considered ill-formed,
|> > rather than cause "undefined behavior." These cases are certainly detectable
|> > at compile time.
|> > i = v[i++];
|> > i = ++i + 1;
|>
|> It can't be detected at compile time in the general case. Example:
|> *p = *q++; // what do these point to?
|> It doesn't seem worthwhile to try to define exactly those cases where
|> it can be detected and then make those ill-formed. Instead, it is
|> left as a "quality of implementation" issue. A compiler is free
|> to diagnose violations if it wants to.
A related question: can a compiler refuse to compile the following program:
int
main()
{
int i = 1 ;
if ( i == 0 )
i = ++ i ;
return i ;
}
The line "i = ++ i" is obviously undefined behavior, and anything can
happen if it is executed. But in the above program, it is never
executed. (The above is obviously just an example. In the general
case, it is impossible for a compiler to determine that it is never
executed.)
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Steve Clamage <stephen.clamage@Eng.Sun.COM>
Date: 1997/04/30 Raw View
Paul D. DeRocco wrote:
>
> Valentin Bonnard wrote:
>
> > > a) Flowing off the end of a value-returning function should not produce
> > > undefined behavior -- it should make the program ill-formed. This is
> > > certainly always detectable at compile time.
> >
> > It's absolutly impossible; only special cases can be detected.
>
> Hmmm. Can you give me an example of a situation where the compiler
> couldn't detect this? I can't think of one.
I posted a somewhat silly example earlier. Here is a more realistic one:
extern int g(int);
int f(int i)
{
for( int j = 0; j < 128; ++j ) {
i = g(i);
if( abs(i) < 2 ) return j;
}
}
Can function f exit by falling off the end? The compiler cannot tell.
Maybe function g always returns 0.
Now suppose everything about the loop is known at compile time:
for ( int j = 0; j < 128; ++j ) {
i /= 2;
if( abs(i) < 2 ) return j;
}
If ints are no larger than 128 bits, this loop will always exit
via the return, and any code following the loop is unreachable.
Do we want to insist that the compiler always make such an
analysis? The compiler would need elaborate theorem proving
and symbolic execution capability in order to determine whether
function f can ever exit improperly.
But it is even worse than that. Even without unknown functionality
(as with function g), the general problem of determining whether
a function can exit improperly reduces to solving the Halting Problem.
We know that is impossible in the general case.
--
Steve Clamage, stephen.clamage@eng.sun.com
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Alexandre Oliva <oliva@dcc.unicamp.br>
Date: 1997/04/30 Raw View
John David Galt writes:
> [stmt.iter]:
> The syntax of "for" appears to require that for-init-statement be non-empty.
> I assume this is a mistake rather than an intended change. Please clarify.
for-init-statement may either be an expression-statement or a
simple-declaration. An expression-statement is an optional expression
followed by a mandatory semicolon, so the initialization is actually
optional, but the semicolon is mandatory as it should be.
> [stmt.jump]:
> The [note] is, or ought to be, in error. Calling exit() should guarantee
> destruction of all class objects with automatic duration. In existing
> practice, that behavior (and the corresponding treatment of open files) is the
> distinction between exit() and abort() (or on some systems, between exit() and
> _exit()).
Objects with automatic duration are usually allocated in the stack, so
it would be quite hard to require their destruction, and would make
multi-threaded implementations close to impossible. Only stack
unwinding destructs automatic objects, and exit should not be required
to behave as if main were enclosed in a try-catch block, and exit
thrown an exception that only this block could catch. Haven't you
confused automatic storage with static storage duration?
> [stmt.return]:
> a) Flowing off the end of a value-returning function should not produce
> undefined behavior -- it should make the program ill-formed. This is
> certainly always detectable at compile time.
That could lead to annoying errors if a function or method is not
supposed to return. Sometimes you just can't provide a valid return
value:
void quit() {
exit(1);
}
// in another translation unit
extern void quit();
class bar {
bar(const string&);
};
class foo {
foo(class bar&);
};
foo checkerror(ostream& o, const string& s) {
if (s.length() > 0) {
o << s << endl;
if (s == "ok")
return foo(bar(s));
else if (s != "fine")
return foo(bar("ok"));
else
throw s;
} else {
endprogram();
}
// should flowing off the function be an error?
// return foo(); // since this would not compile
}
--
Alexandre Oliva
mailto:oliva@dcc.unicamp.br mailto:aoliva@acm.org
Universidade Estadual de Campinas, SP, Brasil
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: jimX.hyslopX@leitchX.com (Jim Hyslop)
Date: 1997/05/01 Raw View
In article <33669422.13C8@ix.netcom.com>,
strip_these_words_pderocco@ix.netcom.com says...
> Valentin Bonnard wrote:
> > > [stmt.return]:
> > > a) Flowing off the end of a value-returning function should not produce
> > > undefined behavior -- it should make the program ill-formed. This is
> > > certainly always detectable at compile time.
> >
> > It's absolutly impossible; only special cases can be detected.
>
> Hmmm. Can you give me an example of a situation where the compiler
> couldn't detect this? I can't think of one.
Assuming the convention of returning an int in the AX register:
int MyFunc()
{
// do some stuff
asm {
// do some more stuff, this time in assembler
mov ax, [some value];
// now do some more stuff that doesn't touch AX
}
}
AX holds the return value, but no C++ return statement was issued. This
requires the compiler to be smart enough to detect that the AX register
was loaded with a value, and that the programmer meant that the value
loaded should be the return value. Can the compiler assume this,
especially with code between the "mov ax" and end of function?
Of course, I suppose this particular example could be rewritten as:
int MyFunc()
{
int iRet;
// do some stuff
asm {
mov ax, [some value];
mov iRet, ax;
//...
}
return iRet;
}
--
Jim Hyslop
Xjim.Xhyslop@leitchX.com
remove all X to email me
Rap: a form of noise sometimes mistaken for music. This mis-spelling is
quite common, as the leading "C" is silent.
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/05/01 Raw View
James Kanze <james-albert.kanze@vx.cit.alcatel.fr> writes:
>A related question: can a compiler refuse to compile the following program:
>
> int
> main()
> {
> int i = 1 ;
> if ( i == 0 )
> i = ++ i ;
> return i ;
> }
No. That is a well-formed program whose behaviour is well-defined.
The compiler is allowed to issue whatever warnings it likes, but it
must "accept and correctly execute" the program.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: bbadger@jade.ssd.hcsc.com (Bernard Badger)
Date: 1997/05/01 Raw View
[As usual, a very good posting, Stephen!]
In article <199704281730.KAA00515@taumet.eng.sun.com>
Stephen.Clamage@eng.sun.com (Steve Clamage) writes:
In article AA04555@waltz.rahul.net, John David Galt <jdg@rahul.net> writes:
[Major SNIP]
> [expr.mul]:
> Leaving the results of / and % (that is, the sign of the remainder)
> undefined for negative operands is a dumb idea, because it makes it
> difficult to write portable code.
The rule is that way because that is the rule in C. Although
some languages do define the result, different languages define
the result differently. Compatibility with C is important, and
the rule allows the C and C++ implementations to use the result of
the hardware divide. (Different platforms give different results.)
We try very hard to avoid C incompatibility that would lead to
programs valid in both C and C++ but with different meanings.
> [expr.shift]:
> For shift operators << and >>:
> a) Integral promotion should be optional (implementation-defined).
> It is not necessary or helpful to promote the right operand on most
> machines.
> b) Right-shifting a negative signed value should fill vacated bits
> with ones. (The actual value this result represents would still be
> implementation-defined, but this statement would make each bit
> predictable.)
The rules are inherited from C, and allow the hardware shift to be used.
If C++ completes the definitions of /, %, << and >> by supplying
requirements to the undefined parts, then it isn't, technically,
incompatible with C. If there were good reasons to fix these
omissions, then the C++ standard could do so without violating C
compatibility. For example, if C++ defined (a%b) to always return the
result in the sign of b, this would be compatible with the current C
standard.
On the other hand, if a user has a non-conforming C program that uses the
implementation-defined meaning of a construct, he might like that
same implementation-defined meaning to be available in C++, too.
If C++ requires more than C, then C++ is not (necessarily) free to
have the same implementation-defined behavior.
To explain why C++ doesn't define some of the things that C leaves
implementation-defined, you have to invoke some other reason than just
"C compatibility" . Those reasons, could be the _same_ reasons that led
the designers of C to allow implementation-defined behaviors, but
they are not "C compatibility".
(You may agree with all of this, and have just used the phrase
"inherited from C" to mean something like "inherited from C, for
compatibility and for all the same reasons that C made that choice,".
But since John David Galt was questioning the choice that C made, I
felt that you should not use the argument from "C compatibility" when
C has left this choice open.)
--
Bernard A. Badger bbadger@mail.ccur.com
11. Thou shalt not Spam!
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com>
Date: 1997/05/01 Raw View
Jim Hyslop wrote:
>
> Assuming the convention of returning an int in the AX register:
Well, all bets are off when you use in-line assembler. I don't expect
the compiler to assume or optimize _anything_ in that case, although I'm
gratified to report that sometimes they at least notice what registers
are use, and don't use them in surrounding C++ code. Sometimes.
--
Ciao,
Paul
(Please send e-mail to mailto:pderocco@ix.netcom.com instead of the
return address, which has been altered to foil junk mail senders.)
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Steve Clamage <stephen.clamage@eng.sun.com>
Date: 1997/05/02 Raw View
Bernard Badger wrote:
>
> If C++ completes the definitions of /, %, << and >> by supplying
> requirements to the undefined parts, then it isn't, technically,
> incompatible with C.
It might force C and C++ implementations on the same platform to be
incompatible, which is what I really meant. The C compiler is allowed
to pick a definition for the sign of the remainder operator that is
most efficient, or most compatible with other software on the
platform. Since languages and platforms differ in that regard, any
more-explicit rule we mandate for C++ will be incompatible with some C
compilers on some platforms.
The term "C compatibility" as used in the C++ Committee is understood
to include the idea that a program valid in both C and C++ has the
same meaning in both languages.
--
Steve Clamage, stephen.clamage@eng.sun.com
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: ark@research.att.com (Andrew Koenig)
Date: 1997/05/02 Raw View
In article <BBADGER.97May1101354@jade.ssd.hcsc.com> bbadger@mail.ccur.com writes:
> If C++ completes the definitions of /, %, << and >> by supplying
> requirements to the undefined parts, then it isn't, technically,
> incompatible with C.
... unless the C committee went and decided to define it differently
in a subsequent revision of the C standard.
--
--Andrew Koenig
ark@research.att.com
http://www.research.att.com/info/ark
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: tony@online.tmx.com.au (Tony Cook)
Date: 1997/05/02 Raw View
John David Galt (jdg@rahul.net) wrote:
: This is based on the April '96 draft, which is the latest version I have.
You should really get the latest version.
: [lex.phases]
: * When (in what phase) are digraphs [lex.digraph] converted to the
: characters they represent? ([lex.phases] says that trigraphs are converted in
: Phase 1, but says nothing about digraphs.) [lex.key], at (2.8.4), says they
: are "converted to a single token in translation phase 7", but if that is true,
: then "%:" (representing '#') could not be legally used AT ALL! Toss out "%:"
: and "%:%:", and then it would make sense to process digraphs in Phase 7; but
: whenever it is done, that time should be stated here.
The digraphs are simply alternate reserved tokens with the same
meaning as existing tokens. They are never replaced with the original
tokens, ie. the string "<:" has three characters '<', ':' and '\0',
not two.
: * What is the order of evaluation of preprocessing directives? (The draft
: simply lumps them together in Phase 4.) The standard ought to require that
: conditionals (#if and its relatives) are evaluated first, so that code which
: is disabled by #if would not be subject to any further processing. (Some
: implementations now refuse to compile code which contains #pragma directives
: unknown to that system, even if they are #if-ed out. The standard should not
: allow implementations to do that.)
I would say this is already covered by [cpp.cond] paragraph 6.
: [lex.digraph]
: (See also the first item under each of [lex.phases] and [lex.literal].)
: * Why not categorize the digraphs and trigraphs together, since they serve
: the same purpose? Why have both for '{', '}', '[', ']', '#', '|', '^', '~'?
They don't serve the same purpose. The trigraphs convert to
characters while digraphs are simply alternate spellings of the same
token.
: * The set of digraphs appears to assume that the seven characters above,
: plus '&' and '!', are not in the source character set on some systems. Given
: that assumption, there ought to be digraphs for '&&=' and '||='.
&&= and ||= are not C++ operators.
: * The suffix '_eq' is used inconsistently: not_eq is inequality, but the
: other *_eq operators are compound assignments. Let's change the suffix of the
: assignments to '_assign'.
I believe these are inherited from an Addendum to ISO C. I believe
the existing tokens are more usable, but that's just an opinion.
: * The prefix 'bit', which distinguishes _some_ bitwise operations from
: their logical counterparts (example: 'bitand' vs. 'and'), is not used
: consistently. Let's either apply it to ALL bitwise operations (making them
: bitcompl, bitnot, bitxor, bitand_assign, bitor_assign, and bitxor_assign), or
: eliminate it and put a 'bool' or 'log' prefix on the two logical operations.
Only 'and' and 'or' have logical and bitwise variants.
: [lex.key]
: * 'new' and 'delete' are reserved keywords. They should not also appear in
: the list of "preprocessing-op-or-punc", unless I've missed something.
: * 'new[]', 'delete[]', 'new<%%>', and 'delete<%%>' should not appear in the
: list of "preprocessing-op-or-punc" because they are not single tokens, and
: their component parts are already listed as reserved.
This appears to have been done in the latest draft.
: * Why are the digraphs, but not the trigraphs, listed as "preprocessing-op-
: or-punc"?
I think I've said 'trigraphs are characters, digraphs are tokens'
often enough.
: [lex.literal]
: * If any digraphs are processed in Phase 1 (and thus, within character and
: string literals), there ought to be backslash escape-sequences, usable in a
: char or string literal, to represent the actual characters that begin those
: digraphs. (Example: If '<%' is recognized in strings, then '\%' is needed to
: represent '%'.)
Since these are tokens they aren't substituted in strings.
: [expr]
: * "Operator overloading shall not modify the rules for the built-in
: operators, that is, for operators applied to types for which they are defined
: by the language itself." (5.3) Does this mean that I _can_ define:
: float operator % (float, float)
: since it is not defined by the language? I'm for it!
neat! <grin>
: [expr.new], [expr.delete]:
: The draft tells us how to declare placement forms of 'new' and 'delete'
: operators (13.5), and the syntax for 'new' (5.3.4.1) shows how to call
: placement 'new'. However, the syntax for 'delete' (5.3.5.1) does not include
: placement arguments, and specifies that it can't be used on objects created by
: placement 'new'. This would appear to imply that:
: a) these objects can never be deleted, and
: b) placement 'delete' can never be called explicitly, and is only used when
: implicitly called because placement 'new' has thrown an exception (5.3.4.18).
: If these assumptions are not true, then [expr.delete] needs to be expanded
: to show how to use placement 'delete'. If b) is true but a) is not, then
: [expr.delete] needs to be amended to show how to delete objects that were
: created by placement 'new'. If both are true, then [expr.new] should say so.
This has improved. There are now placement 'operator delete'
functions, but these are only used to release the memory for an object
when an exception is thrown when constructing an object created with a
placement operator new. There is no 'placement delete' expression,
but you can destroy such objects as you have always been able to: with
an explicit destructor call and a call to your custom deallocator.
: [expr.shift]:
: For shift operators << and >>:
: a) Integral promotion should be optional (implementation-defined). It is
: not necessary or helpful to promote the right operand on most machines.
: b) Right-shifting a negative signed value should fill vacated bits with
: ones. (The actual value this result represents would still be implementation-
: defined, but this statement would make each bit predictable.)
This would also change the behaviour of existing implementations.
: [stmt.iter]:
: The syntax of "for" appears to require that for-init-statement be non-empty.
: I assume this is a mistake rather than an intended change. Please clarify.
The expression in an expression statement is optional.
: [stmt.return]:
: a) Flowing off the end of a value-returning function should not produce
: undefined behavior -- it should make the program ill-formed. This is
: certainly always detectable at compile time.
This is the case in the latest draft
: b) If a "return" is not allowed in a constructor or destructor, say so
: here. (I think it ought to be allowed, which would mean that Borland C++ is
: non-conforming.)
The draft says return is permitted in a constructor or destructor.
: [dcl.asm]:
: IMHO, the 'asm' keyword does not belong in the standard. It should be
: considered an extension if it exists.
: If you must include it, it should be defined as having these two formats,
: because they represent existing practice:
: asm any_text_not_beginning_with_a_left_brace newline
: asm { any_text_not_containing_unmatched_unquoted_braces }
: A semicolon does not terminate the first form. Thus, translation phase 2
: must preserve newline characters which are used for this purpose.
PC compilers use the forms you give. I believe gcc uses something
similar to the form given in the draft.
: [lib.support.types]
: Why can't NULL be defined as (void*)0 ? That def should be _required_.
Briefly, because (void*) is not impicitly converted to other types,
eg:
int *pi = NULL; // error if NULL is (void *)0
--
Tony Cook - tony@online.tmx.com.au
100237.3425@compuserve.com
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/05/02 Raw View
bbadger@jade.ssd.hcsc.com (Bernard Badger) writes:
|> To explain why C++ doesn't define some of the things that C leaves
|> implementation-defined, you have to invoke some other reason than just
|> "C compatibility" . Those reasons, could be the _same_ reasons that led
|> the designers of C to allow implementation-defined behaviors, but
|> they are not "C compatibility".
Yes and no. I think that the general position is that problems in the C
language should be corrected by the C standards committee, and the
corrections adopted into C++, rather than have the C++ committee make
the corrections. Personally, at least, this is the way I would like to
see things happen. Imagine the results, for example, if C++ "fixed" a
particular problem one way, and the C committee adopted a different
solution.
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: "Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com>
Date: 1997/05/02 Raw View
John David Galt wrote:
>
> [expr.mul]:
> Leaving the results of / and % (that is, the sign of the remainder)
> undefined for negative operands is a dumb idea, because it makes it difficult
> to write portable code. I realize that this was a hot political topic, but
> any choice would be preferable to copping out. I suggest this definition:
> (Given P > 0) X % P >= 0; X % (-P) <= 0.
> If this is left undefined, at least please add library functions that _are_
> predictable. I suggest:
> int pmod(int x, int y) is always >= 0;
> int smod(int x, int y) has the same sign as y;
> int pdiv(int x, int y) division with remainder = pmod(x,y)
> int sdiv(int x, int y) division with remainder = smod(x,y)
I agree with this suggestion. In fact, I'd like to see a bunch more of
these, including quo and rem, which do what * and / do when they don't
do div and mod, along with fractional multiplication, the ability to
multiply two numbers and get a result with twice as many bits, a
multiply-divide function (a*b/c) that maintains the extra precision of
the intermediate result, and so on. Implementations should treat them as
intrinsic functions that compile into code as efficient as built-in
operators (i.e., inline code).
> [expr.shift]:
> For shift operators << and >>:
> a) Integral promotion should be optional (implementation-defined). It is
> not necessary or helpful to promote the right operand on most machines.
It's not necessary actually to _do_ anything to promote the right
operand, since it only has to behave "as if" it were promoted.
> b) Right-shifting a negative signed value should fill vacated bits with
> ones. (The actual value this result represents would still be implementation-
> defined, but this statement would make each bit predictable.)
Most machines do this "correctly," but it seems a burden to require
oddball machines to simulate the behavior of two's complement machines
if it isn't natural for it.
A similar argument can be made against something I've occasionally
wanted, which is interpreting a shift by a negative amount as a shift in
the opposite direction. Since most machines won't do this naturally, it
would be inefficient to require compilers to spit out a bunch of extra
code that would never be executed, every time someone shifts by a
variable amount whose type is signed but is always positive in practice.
> [dcl.typedef],[dcl.fct]:
> I notice a lack of any language forbidding declaration of a function using a
> type identifier defined by typedef, as in:
> typedef int T(int,int);
> T func, *fp;
> I hope this was an intentional change; I'm for it, because it allows the
> programmer to have the compiler enforce agreement between the typedef and the
> actual function. However, I agree with not allowing the _definition_ of the
> function to be in this form.
> Perhaps a cleaner way of doing this is to allow typeof(name) to be used as a
> type identifier in declarations. I favor that too. The above would then be:
> int func(int a, int b);
> typeof(func)* fp;
> To this end, delete [temp.arg] (14.8) paragraph 7.
I've often wanted typeof(). Has there been much discussion of such an
operator? I think its effect can be done with templates, though.
I'm not sure I like the idea of being able to declare functions this
way, though, because you have to append an exception-specification to
the declarator, and that would look funny in the absence of the visual
cues usually associated with function declarations, i.e., the
parenthesized argument list:
int (*fp)(int, int) throw(foo); // fine
typedef int T(int, int);
T *fp throw(foo); // looks strange
But that's purely an aesthetic opinion.
> [dcl.asm]:
> IMHO, the 'asm' keyword does not belong in the standard. It should be
> considered an extension if it exists.
> If you must include it, it should be defined as having these two formats,
> because they represent existing practice:
>
> asm any_text_not_beginning_with_a_left_brace newline
>
> asm { any_text_not_containing_unmatched_unquoted_braces }
>
> A semicolon does not terminate the first form. Thus, translation phase 2
> must preserve newline characters which are used for this purpose.
In Borland, a semicolon does terminate the first form, and I like that.
I've created a header that I use all the time, called casm.h, which
defines shorthands for all the x86 mnemonics:
#define Aaa asm aaa
#define Aad asm aad
#define Aam asm aam
.
.
.
#define Xlat asm xlat
#define Xlatb asm xlatb
#define Xor asm xor
Then, I tend to write multiple assembly language instructions on a line:
int timesover(int x, int y, int z) {
Mov eax, x; Imul y; Idiv x;
return _EAX;
}
I never put multiple C statements on a line, but with assembler it makes
sense since multiple instructions represent what you'd write in a single
higher-level statement if the language had the right constructs. I'd
hate to lose that ability. Of course, the standard can't _require_ that
a semicolon terminate an asm construct, because it may have a specific
meaning to the assembler, but it shouldn't prohibit it, since most
assemblers don't use semicolons (other than for comments).
--
Ciao,
Paul
(Please send e-mail to mailto:pderocco@ix.netcom.com instead of the
return address, which has been altered to foil junk mail senders.)
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: David Vandevoorde <daveed@vandevoorde.com>
Date: 1997/05/03 Raw View
James Kanze wrote:
[...]
> Imagine the results, for example, if C++ "fixed" a
> particular problem one way, and the C committee adopted a different
> solution.
I believe this has already happened. E.g., the complex type
in C99 is different from the templates of C++. I'm not even
sure the bool-type and/or the inline specifiers are 100%
compatible (they might be).
Daveed
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: David Chase <chase@world.std.com>
Date: 1997/05/03 Raw View
> Bernard Badger wrote:
> > If C++ completes the definitions of /, %, << and >> by supplying
> > requirements to the undefined parts, then it isn't, technically,
> > incompatible with C.
This problems (the implementation-definedness of / and %) has annoyed
me for years. The basic cost of hardware division/remainder (not to
be confused with division and remainder in the source code, pre-
optimization) is high enough, and the relative frequency is low enough,
that it will not make a difference to anyone (except perhaps certain
well-known comp.arch curmudgeons) if it costs an extra cycle or two to get
division and remainder "right".
Steve Clamage wrote:
> It might force C and C++ implementations on the same platform to be
> incompatible, which is what I really meant. The C compiler is allowed
> to pick a definition for the sign of the remainder operator that is
> most efficient, or most compatible with other software on the
> platform. Since languages and platforms differ in that regard, any
> more-explicit rule we mandate for C++ will be incompatible with some C
> compilers on some platforms.
But this is already true, since you could have two C compilers on the
same platform which used different choices for % and /. The reason
you don't worry about this (and I agree, it is not a problem, except
for a standards weenie) is because nobody does that, and most C compilers
agree anyway. At least, I think that they agree; everywhere that I've
looked, they seem to follow the Fortran rule:
x/y is the integer closest to the mathematical quotient and
between zero and the mathematical quotient inclusively. E.g.,
(-8)/3 = -2.
If, in practice, most C compilers follow this rule, why not adopt it,
and make life easier for C++ programmers? No PORTABLE C program can
rely on these operators having a consistent definition, anyway, so
little has been lost.
I think the leaving the exact definition implementation-defined is
Also at odds with more recent software development practices; people
seem to care lots more about bug-free portability from one platform
to another than they do about porting code from C to C++. I realize
that this was one of the original goals, but, to put it diplomatically,
you guys have been at this for an awful long time, and perhaps things
have changed a little bit.
> The term "C compatibility" as used in the C++ Committee is understood
> to include the idea that a program valid in both C and C++ has the
> same meaning in both languages.
In this case, you are relying on an implementation-defined choice;
this means that though it *could* have the same meaning, it need not
have the same meaning. If, for C++, the standard decided to follow
one rule or the other for / and %, that statement remains true: the
meaning could be the same (a C compiler for which they agreed would
still be a C compiler) but that need not be true. Is this
implementation-defined behavior given special dispensation, or is
this a requirement for all implementation-defined behavior common to
C and C++ programs?
Speaking in terms of language-adoption pragmatics, one thing that
drove me away from C++, and has made me enjoy working in Java, is
the gratuitous variation between different vendors' C++ compilers.
On the last C++ software project I worked on, we ended up using g++
almost everywhere, simply because the code wouldn't port otherwise.
It does not matter what the reasons for this were; the code would
not port, the compilers did not diagnose any incompatibilities, it
was not cost-effective to even file bug reports. Anytime we hit
a problem, the fastest way to resolve it was to bring up g++ on the
platform in question. This is probably not the outcome desired
by people working on C++ compilers who aren't affiliated with the
FSF or Cygnus support.
David Chase
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: John David Galt <jdg@rahul.net>
Date: 1997/04/26 Raw View
This is based on the April '96 draft, which is the latest version I have.
[lex.phases]
* When (in what phase) are digraphs [lex.digraph] converted to the
characters they represent? ([lex.phases] says that trigraphs are converted in
Phase 1, but says nothing about digraphs.) [lex.key], at (2.8.4), says they
are "converted to a single token in translation phase 7", but if that is true,
then "%:" (representing '#') could not be legally used AT ALL! Toss out "%:"
and "%:%:", and then it would make sense to process digraphs in Phase 7; but
whenever it is done, that time should be stated here.
* When are the '#' (stringize) and '##' (token pasting) operators
executed? (Common sense says it is in Phase 4, because '#' expands a macro
into a string literal which is one token, and '##' creates a single token
after macro expansion. But this, too, should be stated here.)
* What is the order of evaluation of preprocessing directives? (The draft
simply lumps them together in Phase 4.) The standard ought to require that
conditionals (#if and its relatives) are evaluated first, so that code which
is disabled by #if would not be subject to any further processing. (Some
implementations now refuse to compile code which contains #pragma directives
unknown to that system, even if they are #if-ed out. The standard should not
allow implementations to do that.)
* The first sentence of 2.1.7, "White-space characters separating tokens
are no longer significant", would seem to mean that I cannot write:
x = j + ++k;
and have it parse correctly. I suggest moving this sentence to the start of
Phase 6 and modifying it to read, "White-space characters between tokens are
no longer significant, but this does not cause tokens to be combined, except
as follows [in the existing Phase 6 text]."
[lex.digraph]
(See also the first item under each of [lex.phases] and [lex.literal].)
* Why not categorize the digraphs and trigraphs together, since they serve
the same purpose? Why have both for '{', '}', '[', ']', '#', '|', '^', '~'?
* The set of digraphs appears to assume that the seven characters above,
plus '&' and '!', are not in the source character set on some systems. Given
that assumption, there ought to be digraphs for '&&=' and '||='.
* The suffix '_eq' is used inconsistently: not_eq is inequality, but the
other *_eq operators are compound assignments. Let's change the suffix of the
assignments to '_assign'.
* The prefix 'bit', which distinguishes _some_ bitwise operations from
their logical counterparts (example: 'bitand' vs. 'and'), is not used
consistently. Let's either apply it to ALL bitwise operations (making them
bitcompl, bitnot, bitxor, bitand_assign, bitor_assign, and bitxor_assign), or
eliminate it and put a 'bool' or 'log' prefix on the two logical operations.
[lex.key]
* 'new' and 'delete' are reserved keywords. They should not also appear in
the list of "preprocessing-op-or-punc", unless I've missed something.
* 'new[]', 'delete[]', 'new<%%>', and 'delete<%%>' should not appear in the
list of "preprocessing-op-or-punc" because they are not single tokens, and
their component parts are already listed as reserved.
* Why are the digraphs, but not the trigraphs, listed as "preprocessing-op-
or-punc"?
[lex.literal]
* If any digraphs are processed in Phase 1 (and thus, within character and
string literals), there ought to be backslash escape-sequences, usable in a
char or string literal, to represent the actual characters that begin those
digraphs. (Example: If '<%' is recognized in strings, then '\%' is needed to
represent '%'.)
* The definition of each type of literal should reference <climits> and/or
numeric_limits, which define the set of values allowed. The 'minimum maximum
values' for each of these limits, as now defined in the C standard, should be
shown, and should be binding on all implementations, in both C and C++.
[basic.life]
* This is the first mention of the term 'POD type'; please move its
definition (3.9, paragraph 9) here, or provide a pointer to it from here.
* (3.8, paragraph 5) appears to be a blanket statement that when a class
object goes out of scope, there is no implicit destructor call. (This
contradicts paragraph 8, so I guess it was meant to have a narrower meaning,
but it should be clarified here.) The standard should guarantee an implicit
destructor call, except for objects that have dynamic storage duration and
cases where placement 'new' is used to create an object on top of already
constructed object(s) (thus preventing their implicit destruction) or on top
of an object declared as a different type (thus causing the new object to go
without implicit destruction, and maybe causing the original object's implicit
destructor call to occur anyway, leading to undefined behavior).
[expr]
* "Operator overloading shall not modify the rules for the built-in
operators, that is, for operators applied to types for which they are defined
by the language itself." (5.3) Does this mean that I _can_ define:
float operator % (float, float)
since it is not defined by the language? I'm for it!
* If an expression violates rule 5.4 ("Between the previous and next
sequence point a scalar object shall have its stored value modified at most
once by the evaluation of an expression. Furthermore, the prior value shall
be accessed only to determine the value to be stored."), and this can be
determined from just that one statement and the declarations of the variables
it uses, as in these examples, then the code should be considered ill-formed,
rather than cause "undefined behavior." These cases are certainly detectable
at compile time.
i = v[i++];
i = ++i + 1;
[expr.new], [expr.delete]:
The draft tells us how to declare placement forms of 'new' and 'delete'
operators (13.5), and the syntax for 'new' (5.3.4.1) shows how to call
placement 'new'. However, the syntax for 'delete' (5.3.5.1) does not include
placement arguments, and specifies that it can't be used on objects created by
placement 'new'. This would appear to imply that:
a) these objects can never be deleted, and
b) placement 'delete' can never be called explicitly, and is only used when
implicitly called because placement 'new' has thrown an exception (5.3.4.18).
If these assumptions are not true, then [expr.delete] needs to be expanded
to show how to use placement 'delete'. If b) is true but a) is not, then
[expr.delete] needs to be amended to show how to delete objects that were
created by placement 'new'. If both are true, then [expr.new] should say so.
[expr.mul]:
Leaving the results of / and % (that is, the sign of the remainder)
undefined for negative operands is a dumb idea, because it makes it difficult
to write portable code. I realize that this was a hot political topic, but
any choice would be preferable to copping out. I suggest this definition:
(Given P > 0) X % P >= 0; X % (-P) <= 0.
If this is left undefined, at least please add library functions that _are_
predictable. I suggest:
int pmod(int x, int y) is always >= 0;
int smod(int x, int y) has the same sign as y;
int pdiv(int x, int y) division with remainder = pmod(x,y)
int sdiv(int x, int y) division with remainder = smod(x,y)
[expr.shift]:
For shift operators << and >>:
a) Integral promotion should be optional (implementation-defined). It is
not necessary or helpful to promote the right operand on most machines.
b) Right-shifting a negative signed value should fill vacated bits with
ones. (The actual value this result represents would still be implementation-
defined, but this statement would make each bit predictable.)
[stmt.iter]:
The syntax of "for" appears to require that for-init-statement be non-empty.
I assume this is a mistake rather than an intended change. Please clarify.
[stmt.jump]:
The [note] is, or ought to be, in error. Calling exit() should guarantee
destruction of all class objects with automatic duration. In existing
practice, that behavior (and the corresponding treatment of open files) is the
distinction between exit() and abort() (or on some systems, between exit() and
_exit()).
[stmt.return]:
a) Flowing off the end of a value-returning function should not produce
undefined behavior -- it should make the program ill-formed. This is
certainly always detectable at compile time.
b) If a "return" is not allowed in a constructor or destructor, say so
here. (I think it ought to be allowed, which would mean that Borland C++ is
non-conforming.)
[stmt.ambig]:
Good as far as it goes. However, I would declare the ambiguous cases to be
deprecated, and point out that ALL of them can easily be clarified, either by
prepending a reserved word used only in declarations such as 'auto' or
'struct' (if a declaration was intended), or by changing the initial function-
style cast to one of the forms (type), static_cast<type>, dynamic_cast<type>,
or const_cast<type> (if an expression statement was intended).
[dcl.typedef],[dcl.fct]:
I notice a lack of any language forbidding declaration of a function using a
type identifier defined by typedef, as in:
typedef int T(int,int);
T func, *fp;
I hope this was an intentional change; I'm for it, because it allows the
programmer to have the compiler enforce agreement between the typedef and the
actual function. However, I agree with not allowing the _definition_ of the
function to be in this form.
Perhaps a cleaner way of doing this is to allow typeof(name) to be used as a
type identifier in declarations. I favor that too. The above would then be:
int func(int a, int b);
typeof(func)* fp;
To this end, delete [temp.arg] (14.8) paragraph 7.
[namespace.udir]:
I suggest allowing a list of declarations in one using statement. That is,
using namespace ns1, ns2::x, cl3::y;
should work exactly the same as
using namespace ns1;
using ns2::x;
using cl3::y;
[dcl.asm]:
IMHO, the 'asm' keyword does not belong in the standard. It should be
considered an extension if it exists.
If you must include it, it should be defined as having these two formats,
because they represent existing practice:
asm any_text_not_beginning_with_a_left_brace newline
asm { any_text_not_containing_unmatched_unquoted_braces }
A semicolon does not terminate the first form. Thus, translation phase 2
must preserve newline characters which are used for this purpose.
[dcl.link]:
Taking the address of a function whose linkage is other than C++ or C should
not produce undefined behavior. It should either be considered ill-formed, or
implementation-defined. This is certainly always detectable at compile time.
[class.scope0]:
"If reordering member declarations in a class yields an alternate valid
program", the program should be considered ill-formed, rather than produce
undefined behavior. This is certainly always detectable at compile time.
[class.abstract]:
The rule that calling a pure virtual function results in undefined behavior
is okay if dynamic binding is really needed for that call. However, if the
call is made:
a) from an object of which it is a member, such as
class X { virtual int f(); } obj;
// ...
obj.f();
or
b) from within the constructor or destructor of any class that inherits the
virtual function,
then that call is (or can be) statically bound, so the problem is certainly
always detectable at compile time. Therefore the program should be considered
ill-formed, rather than produce undefined behavior.
[temp.dep]
Nothing should ever hide the name of a template parameter. Either having
the template parameter hide the other name, or requiring a diagnostic if the
conflict occurs at all, is acceptable. Hiding the template parameter isn't.
[temp.param] (14.7 paragraphs 3 and 4) requires this, IMHO.
[temp.point]
(14.3.2 paragraph 12) Infinite recursion in instantiation should not
produce undefined behavior. It should make the program ill-formed. This is
certainly always detectable at compile time, because the template declarations
involved are in scope when it occurs (or if not, the lack of one of them is
itself an error that is certainly always detectable at compile time).
[temp.param]
(14.7 paragraph 6) "A non-type template-parameter shall not be of floating
type." Why? This restriction is pointless and should be removed.
[temp.arg.explicit]
The example in (14.10.1 paragraph 1) appears to use the constructor
Complex::Complex(double) for implicit type-conversion, in direct violation of
the word "explicit" in that constructor's declaration. Please explain or fix.
[cpp.predefined]
Definition of __STDC__ should not be allowed, because some semantics, such
as the precedence of ?: vs. relational operators, are _required_ to behave
differently in standard C and standard C++.
There should be a __STDCPP__.
There should be predefined macros indicating whether special features, such
as exception-handling, signals, and the STL, are present. I suggest using the
macro names POSIX already uses for this purpose, such as _POSIX_EXCEPTIONS.
[lib.support.types]
Why can't NULL be defined as (void*)0 ? That def should be _required_.
John David Galt
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: "Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com>
Date: 1997/04/28 Raw View
John David Galt wrote:
>
> This is based on the April '96 draft, which is the latest version I have.
>
> [lex.phases]
> * When (in what phase) are digraphs [lex.digraph] converted to the
> characters they represent? ([lex.phases] says that trigraphs are converted in
> Phase 1, but says nothing about digraphs.) [lex.key], at (2.8.4), says they
> are "converted to a single token in translation phase 7", but if that is true,
> then "%:" (representing '#') could not be legally used AT ALL! Toss out "%:"
> and "%:%:", and then it would make sense to process digraphs in Phase 7; but
> whenever it is done, that time should be stated here.
I can't help wondering, when I read this part of the proposed standard,
if anyone ever actually uses this stuff. The idea of someone sitting at
an old IBM keypunch machine preparing a C++ program on Hollerith cards,
or typing one in on a rattling old teletype with a big yellow roll of
paper, seems a bit incongruous to me. Are there any semi-modern
environments where digraphs and trigraphs are actually necessary?
--
Ciao,
Paul
(Please send e-mail to mailto:pderocco@ix.netcom.com instead of the
return address, which has been altered to foil junk mail senders.)
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Michael Hudson <sorry.no.email@nowhere.com>
Date: 1997/04/28 Raw View
A long and interesting post. I have a few comments.
John David Galt wrote:
>
> This is based on the April '96 draft, which is the latest version I have.
[snip]
> [expr]
> * "Operator overloading shall not modify the rules for the built-in
> operators, that is, for operators applied to types for which they are
> defined by the language itself." (5.3) Does this mean that I _can_
> define:
> float operator % (float, float)
> since it is not defined by the language? I'm for it!
Sounds good. There are promotion issues as well, however.
[snip]
>
> [temp.param]
> (14.7 paragraph 6) "A non-type template-parameter shall not be of floating
> type." Why? This restriction is pointless and should be removed.
>
I'd guess its because issues of equality are involved in specialization.
Consider:
template <float F> Class { static Func(); };
template <float F> Class<F>::Func() { cout << "hi!"; >
template <> Class<0.333333>::Func() { cout << "lo!"; >
Class<1/3>::Func();
What does this call? Trivial example, but I hope you see my point.
> [lib.support.types]
> Why can't NULL be defined as (void*)0 ? That def should be _required_.
Try using DejaNews to see how many posts there have been on the subject
of NULL (Hint: quite a lot).
--
Regards,
Michael Hudson
Please don't email this address - it's not mine.
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Stephen.Clamage@eng.sun.com (Steve Clamage)
Date: 1997/04/29 Raw View
In article AA04555@waltz.rahul.net, John David Galt <jdg@rahul.net> writes:
>
>This is based on the April '96 draft, which is the latest version I have.
>
See the FAQ for this newsgroup (referenced below) for how to get
a current version of the draft.
> [lex.phases]
> * When (in what phase) are digraphs [lex.digraph] converted to the
> characters they represent?
They aren't. The so-called digraphs are tokens, not characters
requiring conversion. See section 2.5 paragraph 1.
> * When are the '#' (stringize) and '##' (token pasting) operators
> executed? (Common sense says it is in Phase 4, ...
Of course. That's when preprocessing directives are carried out, as
it says in 2.1 paragraph 4.
> * What is the order of evaluation of preprocessing directives? (The draft
> simply lumps them together in Phase 4.) The standard ought to require that
> conditionals (#if and its relatives) are evaluated first, so that code which
> is disabled by #if would not be subject to any further processing.
According to section 16.1 paragraph 6 such lines are skipped. Phases
1-3 of preprocessing must still be performed to find newlines and the
directives that determine the boundaries of the sections to be skipped,
but no further processing is permitted.
> (Some
> implementations now refuse to compile code which contains #pragma directives
> unknown to that system, even if they are #if-ed out. The standard should not
> allow implementations to do that.)
The standard already disallows it in 16.1 and 16.6. (Confoming
compilers may emit warnings about anything at all, but they must
accept and translate valid code.)
> * The first sentence of 2.1.7, "White-space characters separating tokens
> are no longer significant", would seem to mean that I cannot write:
> x = j + ++k;
> and have it parse correctly.
Assuming you mean 2.1 paragraph 7, then no. At that point proprocessing
has completed and the text has already been separated into tokens.
Whitespace, except inside literal strings and character constants,
serves only to separate tokens and preprocessing directives, and
that separation has already been taken into account.
> [lex.digraph]
> (See also the first item under each of [lex.phases] and [lex.literal].)
> * Why not categorize the digraphs and trigraphs together, since they serve
> the same purpose?
Because they are different categories of things, and do not serve
the same purpose. Trigraphs represent alternative ways to specify
individual characters and are resolved during phase 1, even before
newlines are recognized. The so-called digraphs are just tokens,
recognized during phase 3. ("So-called" because many of them
are not the two-character lexemes as their name would imply.)
Regarding your other suggestions about changes to digraphs:
Digraphs are part of ISO standard 646, and were adopted into
C as C standard header <iso646.h>. The C++ committee had no
choice but to accept them as-is. (Altering them would make no
sense.) The C++ committee, after considerable discussion, voted
to make the "digraphs" reserved built-in tokens instead of
macros in a header.
> [lex.key]
> * 'new' and 'delete' are reserved keywords. They should not also appear in
> the list of "preprocessing-op-or-punc", unless I've missed something.
Yes, they are keywords, but they are also operators.
> * 'new[]', 'delete[]', 'new<%%>', and 'delete<%%>' should not appear in the
> list of "preprocessing-op-or-punc" because they are not single tokens,
They are not listed as "preprocessing-op-or-punc" in the current
draft.
> * Why are the digraphs, but not the trigraphs, listed as "preprocessing-op-
> or-punc"?
See above for discussion of trigraphs vs digraphs.
> [lex.literal]
> * If any digraphs are processed in Phase 1 ...
They are not processed in phase 1.
> * (3.8, paragraph 5) appears to be a blanket statement that when a class
> object goes out of scope, there is no implicit destructor call.
That paragraph in the current draft doesn't discuss scope at all.
> [expr]
> * "Operator overloading shall not modify the rules for the built-in
> operators, that is, for operators applied to types for which they are defined
> by the language itself." (5.3) Does this mean that I _can_ define:
> float operator % (float, float)
> since it is not defined by the language? I'm for it!
The rules for the % operator (5.6 paragraph 2) state "the operands of %
shall have integral or enumeration type." That eliminates the
possibility of your proposed operator function.
> * If an expression violates rule 5.4 ("Between the previous and next
> sequence point a scalar object shall have its stored value modified at most
> once by the evaluation of an expression. Furthermore, the prior value shall
> be accessed only to determine the value to be stored."), and this can be
> determined from just that one statement and the declarations of the variables
> it uses, as in these examples, then the code should be considered ill-formed,
> rather than cause "undefined behavior." These cases are certainly detectable
> at compile time.
> i = v[i++];
> i = ++i + 1;
It can't be detected at compile time in the general case. Example:
*p = *q++; // what do these point to?
It doesn't seem worthwhile to try to define exactly those cases where
it can be detected and then make those ill-formed. Instead, it is
left as a "quality of implementation" issue. A compiler is free
to diagnose violations if it wants to.
> [expr.new], [expr.delete]:
> The draft tells us how to declare placement forms of 'new' and 'delete'
> operators (13.5), and the syntax for 'new' (5.3.4.1) shows how to call
> placement 'new'. However, the syntax for 'delete' (5.3.5.1) does not include
> placement arguments, and specifies that it can't be used on objects created by
> placement 'new'. This would appear to imply that:
> a) these objects can never be deleted, and
> b) placement 'delete' can never be called explicitly, ...
It sounds like you are confounding a "placement-delete expression" with
a placement version of "operator delete". There is no "placement-
delete expression", but you can call an operator delete explicity.
> [expr.mul]:
> Leaving the results of / and % (that is, the sign of the remainder)
> undefined for negative operands is a dumb idea, because it makes it difficult
> to write portable code.
The rule is that way because that is the rule in C. Although
some languages do define the result, different languages define
the result differently. Compatibility with C is important, and
the rule allows the C and C++ implementations to use the result of
the hardware divide. (Different platforms give different results.)
We try very hard to avoid C incompatibility that would lead to
programs valid in both C and C++ but with different meanings.
> [expr.shift]:
> For shift operators << and >>:
> a) Integral promotion should be optional (implementation-defined). It is
> not necessary or helpful to promote the right operand on most machines.
> b) Right-shifting a negative signed value should fill vacated bits with
> ones. (The actual value this result represents would still be implementation-
> defined, but this statement would make each bit predictable.)
The rules are inherited from C, and allow the hardware shift to be used.
> [stmt.iter]:
> The syntax of "for" appears to require that for-init-statement be non-empty.
> I assume this is a mistake rather than an intended change.
No, it is correct. A for-init-statement is required, but it is allowed
to be the empty statement, which consists solely of a semicolon.
(Unlike the C grammar, the C++ grammar does not have a semicolon
following the for-init-statement.)
> [stmt.jump]:
> The [note] is, or ought to be, in error. Calling exit() should guarantee
> destruction of all class objects with automatic duration. In existing
> practice, that behavior (and the corresponding treatment of open files) is the
> distinction between exit() and abort() (or on some systems, between exit() and
> _exit()).
Sorry, no. To destroy all auto objects would mean unwinding the stack
all the way back to main. You can do that if you want to, either
by returning normally up the calling chain, or by throwing an
exception caught in main. The distinction between exit and abort is that
exit results in static destructors being called, but abort does not.
> [stmt.return]:
> a) Flowing off the end of a value-returning function should not produce
> undefined behavior -- it should make the program ill-formed. This is
> certainly always detectable at compile time.
No, it is not detectable in the general case. Here is one complete
translation unit:
extern int j;
int f() {
if( j >= 0 ) return j/2;
}
The programmer might know from the program design that j is never
negative. The compiler cannot in general know. (This example
is silly, but I hope you get the point.)
> b) If a "return" is not allowed in a constructor or destructor, ...
Return statements have since at about 1987 been allowed in ctors
and dtors.
> [namespace.udir]:
> I suggest allowing a list of declarations in one using statement. That is,
> using namespace ns1, ns2::x, cl3::y;
> should work exactly the same as
> using namespace ns1;
> using ns2::x;
> using cl3::y;
This idea was discussed and rejected. It isn't clear where to stop
once you allow multiple names per directive. For example:
using ns1::a, ns1:b, ns1::c, ns1::d;
The next request is to avoid needed to repeat the "ns1::" somehow.
You might also want to have the namespace name in a using-directive
become effective upon appearance, like the Pascal "with" statement:
namespace A { namespace B { ... } .. }
using namespace A, B; // meaning "A, A::B"
Instead of getting involved in this level of complication, it was
considered simpler to allow one name per directive.
> [dcl.asm]:
> IMHO, the 'asm' keyword does not belong in the standard.
It is inherited unchanged from C.
> [dcl.link]:
> Taking the address of a function whose linkage is other than C++ or C should
> not produce undefined behavior.
I don't find any such statement in the current draft standard.
> [class.scope0]:
> "If reordering member declarations in a class yields an alternate valid
> program", the program should be considered ill-formed, rather than produce
> undefined behavior. This is certainly always detectable at compile time.
That possibility was considered and rejected because it requires a
factorial-time algorithm. (The compiler would have to evaluate all
possible reorderings of every class definition.) I don't think you
want to pay the price in compilation time. I know I don't. :-)
> [class.abstract]:
> The rule that calling a pure virtual function results in undefined behavior
> is okay if dynamic binding is really needed for that call.
Pure virtual functions will never be called via the virtual mechanism.
For that to happen, the actual object would have to be of a type
with a pure virtual function, and that is impossible by definition.
> However, if the
> call is made:
> a) from an object of which it is a member, such as
> class X { virtual int f(); } obj;
> // ...
> obj.f();
> or
> b) from within the constructor or destructor of any class that inherits the
> virtual function,
> then that call is (or can be) statically bound, so the problem is certainly
> always detectable at compile time.
No, it is not. Any pure virtual function can be defined, in which
case the call is valid. The definition need not be in the current
translation unit, and so might not be known at compile time.
> [temp.dep]
> Nothing should ever hide the name of a template parameter. Either having
> the template parameter hide the other name, or requiring a diagnostic if the
> conflict occurs at all, is acceptable. Hiding the template parameter isn't.
> [temp.param] (14.7 paragraphs 3 and 4) requires this, IMHO.
I can't match your discussion with your references in the current
draft standard.
> [temp.point]
> (14.3.2 paragraph 12) Infinite recursion in instantiation should not
> produce undefined behavior. It should make the program ill-formed. This is
> certainly always detectable at compile time, because the template declarations
> involved are in scope when it occurs (or if not, the lack of one of them is
> itself an error that is certainly always detectable at compile time).
It cannot be detected at compile time in the general case. Recursion
might be due to indirect instantiation. Templates can be "separately
compiled" and the recursion might not be visible during any one compilation.
> [temp.param]
> (14.7 paragraph 6) "A non-type template-parameter shall not be of floating
> type." Why? This restriction is pointless and should be removed.
It is not pointless because the the results of floating-point
arithmetic are allowed to vary. In addition, the compiler is not
required to use the same precision or format as the target machine.
Suppose we allow this:
template< double x > class C { ... };
C< 1.0 / 3.0 > c1;
C< .10 / .30 > c2;
C< 0.3333333333333333 > c3;
On some platorms the three variables will have the same type and on
others they will not. Compilers for the same platform could vary.
This problem appears for each floating-point value not exactly
representable in the platform's format.
> [temp.arg.explicit]
> The example in (14.10.1 paragraph 1) appears to use the constructor
> Complex::Complex(double) for implicit type-conversion, in direct violation of
> the word "explicit" in that constructor's declaration. Please explain or fix.
I don't find such a violation in the current draft.
> [cpp.predefined]
> Definition of __STDC__ should not be allowed, because some semantics, such
> as the precedence of ?: vs. relational operators, are _required_ to behave
> differently in standard C and standard C++.
Different platforms depend on the presence or absence of __STDC__
for different purposes. Requiring or forbidding it to be defined
in C++ would be unacceptable on important platforms.
> There should be a __STDCPP__.
Which would mean what? If you mean standard preprocessing, there
is only one form of preprocessing in C++. If the implementation
describes itself as standard-conforming, it must use the form of
preprocessing defined in the standard. (Neither the C nor C++
standard describes preprocessing as a stand-alone activity, and
neither standard requires an implementation to provide the
results of preprocessing alone.)
> There should be predefined macros indicating whether special features, such
> as exception-handling, signals, and the STL, are present.
The standard requires them all to be present. There is no concept
in the standard of "partial conformance", and no optional features.
(Exception: "Freestanding" implementations are allowed to omit
most of the library. Freestanding implementations have too many
degrees of freedom to be characterized by a few predefined macros.)
> [lib.support.types]
> Why can't NULL be defined as (void*)0 ? That def should be _required_.
It has always been forbidden in C++ because NULL must be implicitly
convertable to any object pointer type. For type safety, there
is no implicit conversion in C++ from void* to any other type.
---
Steve Clamage, stephen.clamage@eng.sun.com
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Oleg Zabluda <zabluda@math.psu.edu>
Date: 1997/04/29 Raw View
Paul D. DeRocco <strip_these_words_pderocco@ix.netcom.com> wrote:
: I can't help wondering, when I read this part of the proposed standard,
: if anyone ever actually uses this stuff. The idea of someone sitting at
: an old IBM keypunch machine preparing a C++ program on Hollerith cards,
: or typing one in on a rattling old teletype with a big yellow roll of
: paper, seems a bit incongruous to me. Are there any semi-modern
: environments where digraphs and trigraphs are actually necessary?
Di/Trigraphs are not about old terminals AFAIK. They are about
national character sets where the code for '{' may be the same
as for 'some national character', in some coding scheme that
may actually predate ascii.
In such situation, di/trigraphs actually look better then the
alternative. I remember working on a terminal (long time ago)
where I had to do this:
#define 'russian sh' begin
#define 'russian shtch' end
because Koi7 ('russian sh') = ascii ('}'), and the C compiler didn't
support appropriate di/trigraphs.
Oleg
--
Life is a sexually transmitted, 100% lethal disease.
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/04/29 Raw View
Stephen.Clamage@eng.sun.com (Steve Clamage) writes:
>John David Galt <jdg@rahul.net> writes:
>>
>> [expr.mul]:
>> Leaving the results of / and % (that is, the sign of the remainder)
>> undefined for negative operands is a dumb idea, because it makes it difficult
>> to write portable code.
>
>The rule is that way because that is the rule in C.
The good news is that this will probably be fixed in C9X,
and if so, the fix will no doubt eventually make its way into C++.
>> [lib.support.types]
>> Why can't NULL be defined as (void*)0 ? That def should be _required_.
>
>It has always been forbidden in C++ because NULL must be implicitly
>convertable to any object pointer type. For type safety, there
>is no implicit conversion in C++ from void* to any other type.
Yes, but defining `(void *)0' to be a null pointer constant and hence
allowing an implicit conversion from `(void *)0' to any other type would
not violate type safety.
The committee considered this proposal, but unfortunately voted against it.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/04/29 Raw View
Michael Hudson <sorry.no.email@nowhere.com> writes:
|> John David Galt wrote:
|> >
|> > This is based on the April '96 draft, which is the latest version I have.
|>
|> [snip]
|>
|> > [expr]
|> > * "Operator overloading shall not modify the rules for the built-in
|> > operators, that is, for operators applied to types for which they are
|> > defined by the language itself." (5.3) Does this mean that I _can_
|> > define:
|> > float operator % (float, float)
|> > since it is not defined by the language? I'm for it!
|>
|> Sounds good. There are promotion issues as well, however.
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/04/29 Raw View
John David Galt <jdg@rahul.net> writes:
> This is based on the April '96 draft, which is the latest version I have.
> [expr]
> * "Operator overloading shall not modify the rules for the built-in
> operators, that is, for operators applied to types for which they are defined
> by the language itself." (5.3) Does this mean that I _can_ define:
> float operator % (float, float)
> since it is not defined by the language? I'm for it!
1. % 1. is 0 (1 % 1), so your operator 'modify the rules' but not
the ones 'for which they are defined'; I think it means 'for which
they can be called'.
> * If an expression violates rule 5.4 ("Between the previous and next
> sequence point a scalar object shall have its stored value modified at most
> once by the evaluation of an expression. Furthermore, the prior value shall
> be accessed only to determine the value to be stored."), and this can be
> determined from just that one statement and the declarations of the variables
> it uses, as in these examples, then the code should be considered ill-formed,
> rather than cause "undefined behavior." These cases are certainly detectable
> at compile time.
> i = v[i++];
> i = ++i + 1;
True in these particular cases, but not in general.
A good compiler can certainly issue a warning.
> [expr.new], [expr.delete]:
> a) these objects can never be deleted, and
> b) placement 'delete' can never be called explicitly, and is only used when
> implicitly called because placement 'new' has thrown an exception (5.3.4.18).
The lack of placement delete is very sad but you can call operator
delete directly.
> [expr.mul]:
> Leaving the results of / and % (that is, the sign of the remainder)
> undefined for negative operands is a dumb idea, because it makes it difficult
> to write portable code.
Agree, but this is a C issue.
> [expr.shift]:
> For shift operators << and >>:
C topic too.
> [stmt.iter]:
> The syntax of "for" appears to require that for-init-statement be non-empty.
> I assume this is a mistake rather than an intended change. Please clarify.
Certainly a bug !
> [stmt.jump]:
> The [note] is, or ought to be, in error. Calling exit() should guarantee
> destruction of all class objects with automatic duration. In existing
> practice, that behavior (and the corresponding treatment of open files) is the
> distinction between exit() and abort() (or on some systems, between exit() and
> _exit()).
I don't understand you point: calling exit() is like crashing; you can
define an Exit_program exception and throw it to exit the porgram if
you want to run dtors:
int main ()
{
try {
do_work ();
}
catch (Exit_program&)
{
cout << "Bye\n";
}
}
> [stmt.return]:
> a) Flowing off the end of a value-returning function should not produce
> undefined behavior -- it should make the program ill-formed. This is
> certainly always detectable at compile time.
It's absolutly impossible; only special cases can be detected.
> b) If a "return" is not allowed in a constructor or destructor, say so
> here. (I think it ought to be allowed, which would mean that Borland C++ is
> non-conforming.)
It's allowed since some time now; Borland should implement this old
change.
> [dcl.asm]:
> IMHO, the 'asm' keyword does not belong in the standard. It should be
> considered an extension if it exists.
> If you must include it, it should be defined as having these two formats,
> because they represent existing practice:
asm should be a reserved keyword; the syntax is implementation
defined in practice.
> [dcl.link]:
> Taking the address of a function whose linkage is other than C++ or C should
> not produce undefined behavior. It should either be considered ill-formed, or
> implementation-defined. This is certainly always detectable at compile time.
I think that this is the intent; undefined behavior can means:
- the program is not correct but it's impossible (or difficult)
to detect that at compile time; the compiler can optimise or
try to catch the error
- this is 'implementation-dependant'; many implementations will
define it, so we don't want to make that ill-formed (otherwise
you'll have to use the compiler in a non-std way to compile
the program) but it isn't implementation-defined either;
compilers will produce a warning
> [temp.point]
> (14.3.2 paragraph 12) Infinite recursion in instantiation should not
> produce undefined behavior. It should make the program ill-formed. This is
> certainly always detectable at compile time, because the template declarations
> involved are in scope when it occurs (or if not, the lack of one of them is
> itself an error that is certainly always detectable at compile time).
In practice it will crash the compiler or generate an error.
And it's certainly not detectable in general (but excessive
recursion is).
> [temp.param]
> (14.7 paragraph 6) "A non-type template-parameter shall not be of floating
> type." Why? This restriction is pointless and should be removed.
Also floats can't appear in compile time constant; this is related
to the fact that the compiler doesn't always work the same math lib
as the runtime one (thus rounding could be different).
> [temp.arg.explicit]
> The example in (14.10.1 paragraph 1) appears to use the constructor
> Complex::Complex(double) for implicit type-conversion, in direct violation of
> the word "explicit" in that constructor's declaration. Please explain or fix.
I can't find it.
> [cpp.predefined]
>
> [lib.support.types]
> Why can't NULL be defined as (void*)0 ? That def should be _required_.
This is very easy: cause it doesn't _work_ !
null should be a reserved keyword.
--
Valentin Bonnard
mailto:bonnardv@pratique.fr
http://www.pratique.fr/~bonnardv (Informations sur le C++ en Francais)
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/04/29 Raw View
"Paul D. DeRocco" <strip_these_words_pderocco@ix.netcom.com> writes:
|> John David Galt wrote:
|> >
|> > This is based on the April '96 draft, which is the latest version I have.
|> >
|> > [lex.phases]
|> > * When (in what phase) are digraphs [lex.digraph] converted to the
|> > characters they represent? ([lex.phases] says that trigraphs are converted in
|> > Phase 1, but says nothing about digraphs.) [lex.key], at (2.8.4), says they
|> > are "converted to a single token in translation phase 7", but if that is true,
|> > then "%:" (representing '#') could not be legally used AT ALL! Toss out "%:"
|> > and "%:%:", and then it would make sense to process digraphs in Phase 7; but
|> > whenever it is done, that time should be stated here.
|>
|> I can't help wondering, when I read this part of the proposed standard,
|> if anyone ever actually uses this stuff. The idea of someone sitting at
|> an old IBM keypunch machine preparing a C++ program on Hollerith cards,
|> or typing one in on a rattling old teletype with a big yellow roll of
|> paper, seems a bit incongruous to me. Are there any semi-modern
|> environments where digraphs and trigraphs are actually necessary?
Yes and no.
Partially, of course, it depends on what you mean by "semi-modern".
I've developped C on machines which didn't have a '{' character; that
was 7 or 8 years ago, but the equipment was new then, and might still be
in use.
More to the point, although local Windows machines may be able to
display ISO 8859-1, and process it internally, the keyboard doesn't have
keys for the special characters. It is possible to generate them using
ALT-SHIFT-something (with a different something on each machine), but
this is painful; using digraphs would be much simpler.
My own solution used to be to load the US keyboard driver when typing
C/C++, but back when I last worked on such machines, I commented a lot
less than today. And my comments generally need characters that aren't
on the US keyboard. My current platforms generally use a US keyboard,
with a compose key to get the characters I need in comments. I rather
think that given the choice (I'm not), I'd prefer using a French
keyboard, and digraphs. (The problem with this, of course, is that my
platforms are Unix, and I'd still need all of the extra characters in
the shell. One of these days, I'll find time to learn how to do keymaps
in emacs, and arrange for text-mode -- which I use when entering
comments -- to emulate a French keyboard.)
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]