James Kuyper wrote:
> Ned Latham wrote:
> > James Kuyper wrote:
> ...
> > > Code anywhere else in your program that has undefined behavior can
> > > legally change the behavior of any other part of your code, including
> > > this one.
> >
> > I'm completeky lost here: how can source code affect gcc?
>
> gcc reads the source code, translates it in accordance with the
> standard, and generates a program that meets the requirements that the
> standard imposes on the results of translating such code. The standard
> doesn't impose any requirements on the results of translating code that
> has undefined behavior - so the fact that gcc's output meets those
> non-existent requirements shouldn't give you the slightest feeling of
> safety. None. Whatsoever.
I have some searching to do. Thanks a lot.
> > > This is not some pedantic, purely theoretical issue - in real
> > > life the way code with undefined behavior actually behaves can be quite
> > > odd and counter-intuitive; "common sense" is not necessarily a useful
> > > guide to what's actually possible.
> >
> > Just what does that term "code with undefined behaviour" mean here?
>
> "undefined behavior" is defined by the standard as identifying "behavior
> for which this International Standard imposes no requirements" (3.27).
> You actually have to read the standard to locate all of the places where
> it says that the behavior is undefined, in order to determine what kinds
> of code fall into that category. By my count, the latest draft of the
> standard that I have access to, N4659.pdf, contains 68 occurrences of
> that term.
I now have a copy, thanks. I was going to print it, but I think I'll
rely on reading it onscreen.
> In itself, that's not quite as bad as it sounds - not all of
> those occurrences represent distinct reasons for code to have undefined
> behavior (though most of them do).
One's easy to guess: what happens when terminator-dependent string functions
are run over character arrays?
> However, the C++ standard cross-references the C standard for virtually
> the entire C standard library, so every occurrence of "undefined
> behavior" in the C standard that applies to it's library might also
> apply to C++. Also, keep in mind that the behavior of many parts of the
> C++ standard library are defined in terms of the behavior of the C
> standard library (for instance, <iostream> heavily cross-references
> <stdio.h>).
Hmm. I avoid almost all of that code, choosing instead low-level file
handling and raw character-level I/O using only low-level routines in
ctype.h, stdio.h and stdlib.h.
> As a result, code which makes no direct use of the C
> standard library might have undefined behavior for reasons that you
> would have to look at the C standard to understand.
As with there being no means in stdio.h for testing file status? I
see no way to avoid that problem without portability problems.
> > Do you mean function
> > pointers (surely you're not talking about self-modifying code)?
>
> There's many ways that function pointers can be involved when code has
> undefined behavior. However, there's also many other ways the behavior
> can be undefined.
Got it.
> > > Unless and until you show us a complete program, preferably as simple as
> > > possible, which demonstrates the problem you're having, we can't rule
> > > out the possibility that the actual problem lies somewhere else in your
> > > code. You can rule it out if you want to, and apparently have already
> > > done so, but I doubt that your decision to do so was well-justified.
> >
> > If you're talking about function pointers,
>
> I wasn't.
>
> > ... it's not difficult to rule out
> > problems in source code. It's doable in self-modifying code too,
> > for that matter.
>
> Ruling out the existence of any problems in any significant body of code
> is essentially impossible.
I see "significant" here as subject to opinion.
> Detecting problems is often easy, but being
> certain that you've found and corrected all such problems is always the
> result of self-delusion.
Depends on how you treat error conditions. I eschew raising exceptions
(I eschew <iostream> because it raises them): instead I use a my own
little library, which includes a class that does all I/O with just two
functions, Read() and Write(). (All file operations are done by the caller
so that the portability bug is removed from the library.) Possible errors
in those two methods are few, easy to se, and usually easy to deal with.
When an error is detected the class raises an error condition *in the
object*, disaqbling it and uniquely describing the error. That's all it
does, except that the total number of possible error conditions is 100:
it includes flow-on error conditions, making a nice trail to follow.
The result is that callers can deal with errors intelligently: they can
begin development querying the status of objects after every operation
and cut back as regions of code become robust.
> You might happen to be right that there are no
> remaining defects, but certainty about that fact can't be justified.
It can with encapsulation and if all the possibilities for error within
a scope are examined.
> Such certainty is, however, a very popular delusion.
If it's a delusion, I share it.