Topic: Undefined versus unspecified
Author: Steve Roy Karmesin <ssr@ccsf.caltech.edu>
Date: 1995/12/09 Raw View
Jerry Coffin wrote:
>
> jcoffin@rmii.com (Jerry Coffin) wrote:
[..snip..]
> Consider a real example of unspecified behavior:
>
> > a = b + c + d;
>
> [ article body that didn't fit the example _at__all_ elided ]
>
> Okay, the order of evaluation here is unspecified. Depending on
> circumstances, we may even be able to detect differences due to
> different orders of evaluation. (e.g. all are doubles, c and d are both
> much smaller than b. Each of c and d being added to b might
> individually have no effect, but adding c and d first might produce a
> number large enough to affect the value of b.)
>
> However, despite the fact that this is unspecified behavior, as long as
> the magnitudes are such that overflow is impossible, the compiler has no
> option to produce code that blows up or causes other behavior unrelated
> to adding some numbers together. It's only leeway in the matter may, at
> most, cause a slightly different numerical result.
Two comments:
If b,c and d above are large then you could get overflow or not depending
on the order of evaluation. So you could get crash and burn directly or not
depending on order of evaluation.
If the order of evaluation can change the result of a==b (or something
similar) then it could produce arbitrarily large changes in execution path.
You are correct above if you are saying that many users will not care about
that change. You are correct in saying that the compiler should be free to
choose whatever order of evaluation it wants unless you insert parentheses.
Dismissing the difference as "a slightly different numerical result" sweeps
a little too much under the rug though, IMHO.
Steve Karmesin
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: jcoffin@rmii.com (Jerry Coffin)
Date: 1995/12/06 Raw View
kanze@gabi-soft.fr (J. Kanze) wrote:
[ ... ]
>I see what you and Steve Clamage are getting at, but strictly speaking,
>from a standards point of view, is there any real difference? If I
>understand you correctly, unspecified means that it will work, but the
>standard does not define what `work' means in this context. So if it
>formats my hard disk (to take the classical example), the vendor can
>simply say: it's not a bug, that's our definition of work.
Not really. Consider a real example of unspecified behavior:
a = b + c + d;
Now, it is unspecified whether the multiplication will be evaluated
before or after the division. Under some circumstances, you may even be
able to detect a diference. (e.g. depending on the magnitudes involved,
floating point accuracy can be affected.)
Now assuming the magnitudes involved are such that no intermediate
result can cause an overflow, then this can't do anything other than
give us a result. Changes in evaluation order may change the accuracy
of the result, but certainly can't reformat your hard disk. By
contrast, if we compute `b*c/d' and d is 0, then the result is
undefined, and something terrible may happen.
Later,
Jerry.
/* I can barely express my own opinions; I certainly can't
* express anybody else's.
*
* The universe is a figment of its own imagination.
*/
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: John Max Skaller <maxtal@suphys.physics.su.oz.au>
Date: 1995/12/06 Raw View
kanze@gabi-soft.fr (J. Kanze) wrote:
>Sean A Corfield (sean@corf.demon.co.uk) wrote:
>
>|> I've highlighted the important difference. Unspecified means it'll work
>|> fine but we're not telling you how; undefined means it might do anything
>|> (including not work at all).
>
>I see what you and Steve Clamage are getting at, but strictly speaking,
>from a standards point of view, is there any real difference? If I
>understand you correctly, unspecified means that it will work, but the
>standard does not define what `work' means in this context. So if it
>formats my hard disk (to take the classical example), the vendor can
>simply say: it's not a bug, that's our definition of work.
No, thats not how it goes. Here's how it goes. GIVEN a particular
implementor binding of the "implementation-defined" parameters
of the abstract machine, each well formed program is required
to exhibit one of a certain set of behaviours (or the compiler isn't
conforming).
0 elements: If the set is empty, the Standard is screwed.
1 element: If the set has exactly one element, the program is said to be
deterministic (contingent on the state of the environment).
SUBSET: If the set is a strict subset of the universal subset,
the program is said to be non-determinisatic and the
corresponding behaviour is said to be "unspecified".
This is misleading because the SET of permitted behaviours
is NOT unspecified, contrarily the range of permitted behaviours
is ALWAYS specified in the Standard (or the Standard is screwed).
UNIVERSAL SET: If the set is the universal set, the program is said to
have undefined behaviour. This is sometimes explicitly
stated, although such statements are always non-normative.
Where it is not possible to deduce anything about the required
behaviour from the Standard, then behaviour is undefined,
which is "undefined behaviour".
SO: it is very simple. You can say "the Standard specifies
the SET of behaviours of ALL well formed programs precisely."
The terminology "well defined", "unspecified" and
"undefined" simply refers to the SIZE of that set, nothing more.
[Caveat: note again that this applies to a particular binding
of the Standard by an implementor; and also that behaviour
is contingent on the environment. Note further that the behaviour
of YOUR program may be more restricted than specified by the
Standard: you may well (have to) rely on non-portable implementation
specified properties of your compiler or envionment.]
--
John Max Skaller voice: 61-2-566-2189
81 Glebe Point Rd fax: 61-2-660-0850
GLEBE NSW 2037 email: maxtal@suphys.physics.oz.au
AUSTRALIA email: skaller@maxtal.com.au
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: James Kanze US/ESC 60/3/141 #40763 <kanze@lts.sel.alcatel.de>
Date: 1995/12/07 Raw View
In article <4a2nvl$nq@natasha.rmii.com> jcoffin@rmii.com (Jerry
Coffin) writes:
|> kanze@gabi-soft.fr (J. Kanze) wrote:
|> [ ... ]
|> >I see what you and Steve Clamage are getting at, but strictly speaking,
|> >from a standards point of view, is there any real difference? If I
|> >understand you correctly, unspecified means that it will work, but the
|> >standard does not define what `work' means in this context. So if it
|> >formats my hard disk (to take the classical example), the vendor can
|> >simply say: it's not a bug, that's our definition of work.
|> Not really. Consider a real example of unspecified behavior:
|> a = b + c + d;
|> Now, it is unspecified whether the multiplication will be evaluated
|> before or after the division. Under some circumstances, you may even be
|> able to detect a diference. (e.g. depending on the magnitudes involved,
|> floating point accuracy can be affected.)
|> Now assuming the magnitudes involved are such that no intermediate
|> result can cause an overflow, then this can't do anything other than
|> give us a result. Changes in evaluation order may change the accuracy
|> of the result, but certainly can't reformat your hard disk. By
|> contrast, if we compute `b*c/d' and d is 0, then the result is
|> undefined, and something terrible may happen.
I agree with what you are saying, but you missed the point of my
statement. No compiler is going to intentionally generate code to
format the hard disk just because you dared to write a program which
invoked undefined behavior. So *practically*, dividing by 0 will not
format your hard disk; if it did, I'd certainly complain to the vendor
(and maybe even sue him, if I could prove that he did it
intentionally), even though he is formally conformant.
On the other hand, suppose that due to an error in the OS, a floating
point exception actually did format the hard disk. If the floating
point exception occurs because I divided by zero, it's my fault, but
if it occurs because the compiler illegally reordered an expression
(thus causing overflow), it's the compilers fault. In both cases,
however, my data is gone.
Within the standard, such distinctions are necessary, because they
tell the compiler implementor which cases he must verify, and where he
can pretend that the programmer knows what he is doing. For the
typical user, however, they really aren't that significant.
Another example of what I am getting at: the C standard declares the
infamous struct hack undefined behavior. In fact, however, it is
widespread in existing code, and I imagine that it also occurs in new
code relatively frequently. The result, of course, is that no one
implements a C compiler where it doesn't work, at least with certain
modes of compile.
In the other direction, it is perfectly legal to have a global
function called read and a variable called far in your (C) code. I
wouldn't do it, at least unless I was 100% sure of all the platforms
my code would ever run on.
This is not to belittle the importance of a standard. In C++, we need
one desparately. But in real life, the standard is just one of the
parameters that you have to consider.
--
James Kanze Tel.: (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils, tudes et r alisations en logiciel orient objet --
-- A la recherche d'une activit dans une region francophone
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: jcoffin@rmii.com (Jerry Coffin)
Date: 1995/12/09 Raw View
James Kanze US/ESC 60/3/141 #40763 <kanze@lts.sel.alcatel.de> wrote:
>In article <4a2nvl$nq@natasha.rmii.com> jcoffin@rmii.com (Jerry
>Coffin) writes:
[ ... ]
>|> Now assuming the magnitudes involved are such that no intermediate
>|> result can cause an overflow, then this can't do anything other than
>|> give us a result. Changes in evaluation order may change the accuracy
>|> of the result, but certainly can't reformat your hard disk. By
>|> contrast, if we compute `b*c/d' and d is 0, then the result is
>|> undefined, and something terrible may happen.
>I agree with what you are saying, but you missed the point of my
>statement. No compiler is going to intentionally generate code to
>format the hard disk just because you dared to write a program which
>invoked undefined behavior. So *practically*, dividing by 0 will not
>format your hard disk; if it did, I'd certainly complain to the vendor
>(and maybe even sue him, if I could prove that he did it
>intentionally), even though he is formally conformant.
Okay, so your position is that even undefined behavior will rarely if
ever do anything really awful, and if it does it'll only be by accident.
I guess a lot of the importance of this depends on what your program is
doing. For instance it's not particularly out of line for the program
to simply get stopped dead with some error like:
SYSDIV0 Errror. Program stopped.
Now depending on the program in question, that often won't be
particularly terrible - it might simply mean restarting an editor or
somesuch. OTOH, in a system that controlled, say, the sewage system for
an entire city, simply stopping is grossly unacceptable behavior, and
might be a much greater disaster than formatting the average hard disk.
(I happen to choose this example largely because it's a job I worked at
for a few years.)
>Within the standard, such distinctions are necessary, because they
>tell the compiler implementor which cases he must verify, and where he
>can pretend that the programmer knows what he is doing. For the
>typical user, however, they really aren't that significant.
I think they're frequently significant -- certainly if I add three
numbers together and I know their range will prevent an overflow, I know
the order of evaluation is unspecified, but it certainly shouldn't
require _anything_ on my part to ensure against _anything_ strange
happening -- the overall results of the action are clearly and well
defined no matter what. The change can produce a slight error, but
nothing more.
>Another example of what I am getting at: the C standard declares the
>infamous struct hack undefined behavior. In fact, however, it is
>widespread in existing code, and I imagine that it also occurs in new
>code relatively frequently. The result, of course, is that no one
>implements a C compiler where it doesn't work, at least with certain
>modes of compile.
This reminds me - I've been meaning to ask. The DWP makes it clear that
the struct hack can't be depended upon with anything but a POD, but does
it actually make it defined for a POD, or does it leave it undefined,
and simply make clear that it'll never work otherwise?
>In the other direction, it is perfectly legal to have a global
>function called read and a variable called far in your (C) code. I
>wouldn't do it, at least unless I was 100% sure of all the platforms
>my code would ever run on.
>This is not to belittle the importance of a standard. In C++, we need
>one desparately. But in real life, the standard is just one of the
>parameters that you have to consider.
I'll certainly agree with that. For one thing, the C and C++ stanards
are from from the only ones around. For quite a bit of code, POSIX may
be a more useful standard overall, and even though `far' is legally in
the user's name space, you're certainly right that ignoring a huge
market (regardless of one's personal feelings toward it) can be a a
foolish decision.
Later,
Jerry.
/* I can barely express my own opinions; I certainly can't
* express anybody else's.
*
* The universe is a figment of its own imagination.
*/
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: Sean A Corfield <sean@corf.demon.co.uk>
Date: 1995/12/01 Raw View
In article <MATT.95Nov30185128@cyclops5.berkeley.edu>,
matt@cyclops5.berkeley.edu (Matt Austern) wrote:
|> Section 1.3 of the draft standard says that undefined behavior is
|> "Behavior, such as might arise upon use of an erroneous program
^^^^^^^^^
|> construct of or erroneous data, for which the standard imposes no
^^^^^^^^^
|> requirements." It also says that unspecified behavior is "Behavior,
|> for a correct program construct and correct data, that depends on the
^^^^^^^ ^^^^^^^
|> implementation. The implementation is not required to document which
|> behavior occurs. [Note: usually, the range of possible behaviors is
|> delineated by the standard.]"
|>
|> Now, as I read these definitions it seems to me that they're the same,
I've highlighted the important difference. Unspecified means it'll work
fine but we're not telling you how; undefined means it might do anything
(including not work at all).
Sean A. Corfield
Object Consultancy Services
C++ - Beyond the ARM - http://uptown.turnpike.net/~scorf/cplusext.html
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]