pete posted:
When "the previous byte" is the last byte of memory.
Hmm...
The C language guarantees that you can have a pointer to "one past the
last element of an array"; therefore the following program is well-formed
and absent of undefined behaviour.
int main(void)
{
char buffer[56];
char *p = buffer + 56;
}
However... in order to facilitate this, it must be possible to store a
particular address in a pointer variable, and for that address to fulfill
the following criteria:
(A) The address is non-null.
(B) The address is not the address of a legitimate object.
You can't have a pointer to "two past the end", so the following code is
broken:
int main(void)
{
char buffer[56];
char *p = buffer + 57;
}
Given that there will always be a legitimate "border address" which
doesn't refer to a legitimate object, we can always assume that when we
increment a valid char pointer, it will always point to the next byte.
Am I right?
No, not in all cases. Let's back up to the original statement by
Michael Mair:
"If you increase a valid pointer to unsigned char by 1, it
points to one past the previous byte (often: the next byte)."
Now let's rewrite your code snippet to match Mike's statement:
int main(void)
{
unsigned char buffer[56];
unsigned char *p = buffer + 55; /* 1: point to last element */
++p; /* 2: point to one past end of array */
++p; /* 3: point two past end of array */
}
The line marked 1: sets the pointer to the address of an existing
unsigned char that the program has the right to read, write, and
modify.
The line marked 2: sets the pointer to the address of one past the end
of the array. There may or may not be a byte there. Any attempt to
dereference that pointer, read or write, is undefined behavior. On
some systems the attempt might well cause the operating system to trap
and terminate the program.
So while this is a "valid unsigned char pointer value", it is not a
"valid pointer to unsigned char", since it is not allowed to be used
to access an unsigned char. Likewise, NULL is a "valid unsigned char
pointer value", but it is not a "valid pointer to unsigned char".
As for your code:
int main(void)
{
char buffer[56];
char *p = buffer + 57;
}
The array has 56 elements, indexed 0 through 55. It is legal to point
to, but not access, buffer + 56, one past the end. It is not legal to
even form a pointer to more than one past the end. The expression
"buffer + 57" produces undefined behavior. The result might well be
an immediate OS termination, although I don't know of any architecture
off-hand where forming, but not dereferencing, an invalid pointer
value traps.
This is a somewhat different case than assuming that either there are
no padding bits in integer types, or that if there are, their values
are irrelevant. There are code efficiencies possible with that
assumption. There are none to be had by forming invalid pointer
values.