Mark McIntyre said:
Absolutely. I can't see the point in any of this posting, except this
bit.
I was trying to figure out what you meant by "Once you start relying on the
behaviour of a
given platform, your code is no longer C.".
Source code is what you build binaries from. Binaries are
implementation-specific. If you compile the source on a lot of different
platforms, the executables might all do the same thing, in which case the
source is portable, or they might not, or you might not even want them to.
Even in the portable case, what the programs are doing internally might be
very different. It'll almost always be different. Even in Hello World,
you've got a string literal. The signedness of the chars, their bit-width,
their values, the representation of the address, are all
implementation-dependent. To know the code is portable you have to figure
out that none of that will actually affect the outcome. With experience,
you don't have to think about it much, but it's there. In other cases the
differences might be much bigger and you do have to work it out.
Or, as I said, you might not want portability. Suppose I have
#include <limits.h>
int main (void) {
if ( CHAR_BIT == 8 ) {
/* code here to output the date */
} else if ( CHAR_BIT == 9 ) {
/* code here to output the words of the Star-spangled Banner */
} else {
int i = 0;
i++ + i++;
}
return 0;
}
Compiled on platform A I get a useful tool to tell me the date. On platform
B I get a useful tool to remind me what comes after the dawn's early light.
On platform C, well who cares. Not portable source, then. But I don't see
why it's not C. If it isn't, what is?
Portability can't come into it, because the definition of portability isn't
an effective test for source code, so you only get a circularity. You have
to analyse behaviour on implementations to draw conclusions about
portability.
If you want to talk about behaviour, what happens when you run a program,
it's not only a function of the source. It's a function of the source and
the implementation and the input.
There is no non-trivial implementation-free behaviour.
If you only want to talk about what the standard says about behaviour, you
can do that as well.
But you aren't talking about behaviour, you're only talking about what the
standard says about behaviour. "The behaviour is undefined" in the standard
only means "if this code is reached, the standard imposes no requirements",
but people quote it as if it said something about the behaviour of the
program. It doesn't: the behaviour of a program might be perfectly
well-defined (on some inputs and implementations or even on all of them) in
spite of this phrase appearing in a clause applicable to a construct that
appears in the code.
A discussion at this level -- what the standard says about the behaviour --
just doesn't get you very far, when you're talking about programs rather
than statements and code fragments. In simple enough cases, it might tell
you the code is portable and tell you what it does. In other simple cases
it might tell you that the code is categorically not portable. Most of the
time in real life it can't tell you anything about anything except
portability and it can't even tell you about that.
To say "The standard says 'The behaviour [of this bit] is undefined' [with
the standard's meaning]" might be indisputably correct, but since it can be
said of most non-trivial programs,
it needs a bit more to make it interesting.