Wolfgang said:
In such system, how can one then access address 0?
That's up to the implementation. Possibly by converting a non-constant
integer expression with a value of 0 into a pointer; the standard does
require that the result be a null pointer; that guarantee only applies
to integer constant expressions with a value of 0.
Possibly by converting an implementation-defined non-zero integer into a
pointer.
If the address of 0 has special meaning (as seems likely on such a
machine), a pointer to that location could possibly be generated by
writing &__special_object_name, or __special_pointer, or by calling a
function which returns a pointer to that object when given the right
arguments.
Making the compiler silently replace the value written in the
text with some other value is something no compiler should do.
You seem to be quite confused about the relationship between the text of
a program and the representation of the values specified by that text.
It is the norm, not the exception, for such replacement to take place.
The literals 12345, "12345", and 12345.0 all correspond to very
different bit patterns when stored in memory; the same is true of
(void*)12345, assuming that it even represents a valid pointer value.
The standard specifies precisely what happens for string literals,
imposes strict requirements for unsigned integer literals, allows a
little more freedom for signed integer literals, allows a lot of freedom
for floating point literals, and leaves the handling of the conversions
of integer values to pointer types almost completely unspecified, except
when the integer is an integer constant expression with a value of 0.
And in the case of pointers it may break pointer arithmetic
severely, or take a lot of conditionals (in the compiler) to get
it right.
You can't legally do pointer arithmetic on null pointers. Why would the
address(es) used to represent null pointers have any impact on pointer
arithmetic?
What you suggest is, that there are two sets of addresses, the
set of addresses "visible" to the source code, and the set of
addresses at execution, and that the mapping is not surjective.
Not really. The source code never contains addresses. It can contain
null pointer constants that are treated as null pointers, and it can
specify conversion of integer values to pointers; that's probably what
you're thinking of code containing addresses. It can also specify the
conversion of a string into a pointer, using sscanf(); I suppose you
might also think of that as code which contains an address.
What happens in each of those cases is up to the implementation, the
standard imposes no requirements on the resulting pointer for any of
those cases except null pointer constants. The standard was deliberately
written this way, because real systems existed when the standard was
first written which don't do things the simple way you apparently
expect, and such systems are still in use today.
Incidentally, what the standard says about null pointer constants does
not prevent the mapping from being surjective on machines where a null
pointer cannot refer to address 0. It's perfectly permissible to have
some other integer value which does convert to a pointer which refers to
address 0; that integer value just can't be 0, at least not when the
integer is an integer constant expression.