J
James Kuyper
James Tursa wrote:
....
Ultimately, nothing more or less than the fact that the standard says
that the behavior is undefined. Because the behavior is undefined,
compilers are allowed to generate code that might fail if such stepping
is attempted (though this is rather unlikely). More importantly,
compilers are allowed to generate code that assumes that such stepping
will not be attempted, and therefore fails catastrophically if it
actually is attempted - the most plausible mode of failure is a failure
to check for aliasing.
Specific details:
Given
double array[2][1];
double *p = (double*)array;
If there is code which sets array[1] to one value, and p[j] to
another value, the compiler not required to consider the possibility
that p[j] and array[1] might point at the same location in memory.
It's allowed to keep either value in a register, or to keep the two
values in different registers. It's not required to make the next
reference to array[1] give the same value as the next reference to p[j].
This is because the behavior would be undefined if 'i' and 'j' had
values that might ordinarily cause you the expect array[1] and p[j]
to refer to the same location. Note: this convoluted wording is
necessary, because if 'i' and 'j' have such values, then at least one of
the two expressions has undefined behavior, rendering it meaningless to
talk about which location that expression actually refers to.
Yes, it is, and the reason is that the standard explicitly allows access
to entirely of an object through lvalues of "unsigned char", and the
behavior of memcpy() is defined in terms of operations on "unsigned
char" lvalues. There is no similar exemption for "double*".
....
OK, that's fine for objects, but that doesn't answer my question. What
is it about 2-dimensional (or multi-dimensional) arrays of double that
does not allow them to be stepped through with a double* ?
Ultimately, nothing more or less than the fact that the standard says
that the behavior is undefined. Because the behavior is undefined,
compilers are allowed to generate code that might fail if such stepping
is attempted (though this is rather unlikely). More importantly,
compilers are allowed to generate code that assumes that such stepping
will not be attempted, and therefore fails catastrophically if it
actually is attempted - the most plausible mode of failure is a failure
to check for aliasing.
Specific details:
Given
double array[2][1];
double *p = (double*)array;
If there is code which sets array[1] to one value, and p[j] to
another value, the compiler not required to consider the possibility
that p[j] and array[1] might point at the same location in memory.
It's allowed to keep either value in a register, or to keep the two
values in different registers. It's not required to make the next
reference to array[1] give the same value as the next reference to p[j].
This is because the behavior would be undefined if 'i' and 'j' had
values that might ordinarily cause you the expect array[1] and p[j]
to refer to the same location. Note: this convoluted wording is
necessary, because if 'i' and 'j' have such values, then at least one of
the two expressions has undefined behavior, rendering it meaningless to
talk about which location that expression actually refers to.
... And
ultimately, I would also ask if it is safe/conforming to use memcpy or
the like to copy values from/to such an array wholesale. e.g., is it
Yes, it is, and the reason is that the standard explicitly allows access
to entirely of an object through lvalues of "unsigned char", and the
behavior of memcpy() is defined in terms of operations on "unsigned
char" lvalues. There is no similar exemption for "double*".