Jens M Andreasen said:
More bullshit!
You are obviously deliberately handwawing, perhaps because you
find it amusing (what do I know?) As far as I can tell, you are
just trolling, but then again, what do I know?
It's a really bad idea to be simultaneously rude and wrong.
C99 6.5.3p4:
The unary * operator denotes indirection. If the operand points
to a function, the result is a function designator; if it points to
an object, the result is an lvalue designating the object. If the
operand has type "pointer to type", the result has type "type".
If an invalid value has been assigned to the pointer, the behavior
of the unary * operator is undefined.
A footnote says:
Among the invalid values for dereferencing a pointer by the unary
* operator are a null pointer, an address inappropriately aligned
for the type of object pointed to, and the address of an object
after the end of its lifetime.
So deferencing a null pointer (as in "x = *p;" above) invokes
undefined behavior. But what does that mean?
C99 3.4.3 (the definition of "undefined behavior"):
undefined behavior
behavior, upon use of a nonportable or erroneous program construct or
of erroneous data, for which this International Standard imposes no
requirements
NOTE Possible undefined behavior ranges from ignoring the
situation completely with unpredictable results, to behaving
during translation or program execution in a documented manner
characteristic of the environment (with or without the issuance of
a diagnostic message), to terminating a translation or execution
(with the issuance of a diagnostic message).
The C90 standard has similar wording, but my copy of the C99 standard
is easier to search and to cut-and-paste from. I can post the C90
standard's wording if you like.
In the code snippet above, "ignoring the situation completely with
unpredictable results" clearly includes the possibility of the
printf("Oops!\n");
statement being executed in the code snippet above.
It could also raise a signal or otherwise abort the program on the
attempt to dereference p. This is probably the most common behavior
on most modern systems.
Undefined behavior is undefined behavior. We sometimes jokingly talk
about "nasal demons", i.e., a conforming implementation could legally
make demons fly out your nose. Obviously no real implementation will
do this, but one that did would not be nonconforming for that reason.
I dare you: In which conforming implementation is it that what you wrote
above true?
I don't know. I was referring to what the standard allows, not to
what any particular real-world implementation does.
But there have been implementations in the past that represented null
pointers as all-bits-zero, didn't trap on attempts to dereference
address zero, and stored some particular value at that address (either
a zero or the string "(null)", I think). On such a system, running
the code snippet above will set x to whatever value happens to be
stored at address 0, and the string "Oops!" will be printed.
I wouldn't be at all surprised if there are current conforming
implementations that behave this way.
Most people around here understand the difference between the language
of a standard, which is almost always vague,
Standards can be vague in places, but I don't believe the C standard
is nearly as vague as you seem to think it is.
and the actual
implementatation, which is an interpretation of the language combined with
common sense (which, as it appears, is not so common anymore.)
Yes, most of us do. The real danger is assuming that everybody else's
"common sense" is the same as yours. Yours, I suspect, is based on
your experience with a relatively limited set of C implementations.
The C language, which is what we discuss here, doesn't have such a
limited scope.
Incidentally, while I was writing this I remembered that I have an
account on a system that I thought *might* behave as I described
above. It turns out that it doesn't, but it still provides an
interesting example.
I compiled and executed the following program on that system:
#include <stdio.h>
int main(void)
{
int *p = NULL;
int x;
x = *p;
printf("Oops!\n");
return 0;
}
and it printed "Oops!". Thinking I had come up with a concrete
example, I modified the program to print the value of x -- and it died
with an access violation error. Apparently the compiler had optimized
out the assignment, and therefore the dereference, because the value
of x was never used (which is a perfectly legal optimization). When I
added code that used the value of x, it could no longer do that
optimization. (The system in question is an old VAX/VMS system; the
VMS DECC compiler performs more aggressive optimizations by default
than the other compilers I tried.)
I get the same behavior on several other systems with:
gcc -O3 -ansi -pedantic -Wall -W tmp.c -o tmp
(In fact, "-O1" is all that's required.)
So this is a real-world case where the program, which invokes
undefined behavior, actually executes the printf statement. It's just
not for the reasons I had originally thought.
Undefined behavior is undefined behavior.