In said:
If a program invokes undefined behavior, does it mean that the entire
program is "undefined behavior", even if that code is never executed?
Or is it only "undefined behavior" at the time the particular code is
executed (and from that point on)?
For example:
void do_undefined(int *pint)
{
*pint = *pint++;
}
int main(int argc,char *argv[])
{
int i;
for ( i=0 ; i < 10 ; i++ )
{
printf("%d\n",i);
fflush(stdout);
if ( i == 8 )
do_undefined(&i);
}
}
Is this program guaranteed to at least print 0 through 8, or does
the undefined behavior in do_undefined() mean that the program can
do something "undefined" before i reaches 8?
Your program is not required to be translated successfully, because of
the
*pint = *pint++;
statement. The more interesting examples are those where the compiler
cannot detect undefined behaviour at translation time:
#include <stdio.h>
#include <stdlib.h>
void foo(int *p, int *q) { *p = *q++; }
int main(int argc, char *argv[])
{
int i;
for (i = 0; i < atoi(argv[1]); i++) {
printf("%d\n", i);
if (i == 8) foo(&i, &i);
}
return 0;
}
This program *may* invoke undefined behaviour in a couple of places,
but whether it does so or not depends exclusively on the way it is
invoked. Therefore, the compiler has no licence to refuse translating it.
At run time, however, if the first program parameter is a number
above 7, you have NO guarantee that this program will print the digits
0 to 8 before something more or less unusual will occur. If the
implementation can determine that the execution path will necessarily
encounter undefined behaviour, all the bets about the program's behaviour
are off. Likewise, if the execution path cannot possibly encounter
undefined behaviour, the program's output must be as specified in the
description of the abstract machine, so this program must work as
expected if its first parameter is a number between INT_MIN and 7.
This is not the *only* possible interpretation of the C standard, but this
is the one preferred in comp.std.c. It is possible to argue that, if the
program's execution is interrupted before foo() is called, the program
doesn't invoke undefined behaviour and, therefore, its output up to that
moment must be the expected one. And, since the program cannot predict
whether its execution will or will not be interrupted before foo() is
called, it cannot assume that undefined behaviour will be ever invoked!
Of course, in practice, nobody bothers detecting undefined behaviour
before it actually happens, so, even if argv[1] is a number above 7 you're
fairly safe if you manage to stop the program execution before foo is
called.
Dan