When the C Standard specifies that certain actions invoke Undefined Behavior, that does has not generally meant that such actions were forbidden, but rather that implementations were free to specify the consequent behaviors or not as they see fit. Consequently, implementations would be free to perform such actions in cases where the Standard requires defined behavior, if and only if the implementations can guarantee that the behaviors for those actions will be consistent with what the Standard requires. Consider, for example, the following implementation of strcpy:
char *strcpy(char *dest, char const *src)
{
ptrdiff_t diff = dest-src-1;
int ch;
while((ch = *src++) != 0)
src[diff] = ch;
return dest;
}
If src
and dest
are unrelated pointers, the computation of dest-src
would yield Undefined Behavior. On some platforms, however, the relation between char*
and ptrdiff_t
is such that given any char* p1, p2
, the computation p1 + (p2-p1);
will always equal p2
. On platforms which make that guarantee, the above implementation of strcpy
would be legitimate (and on some such platforms might be faster than any plausible alternative). On some other platforms, however, such a function might always fail except when both strings are part of the same allocated object.
The same principle applies to the offsetof
macro. There is no requirement that compilers offer any way to get behavior equivalent to offsetof
(other than by actually using that macro) If a compiler's model for pointer arithmetic makes it possible to get the required offsetof
behavior by using the ->
operator on a null pointer, then its offsetof
macro can do that. If a compiler wouldn't support any efforts to use ->
on something other than a legitimate pointer to an instance of the type, then it may need to define an intrinsic which can compute a field offset and define the offsetof
macro to use that. What's important is not that the Standard define the behaviors of actions performed using standard-library macros and functions, but rather than the implementation ensures that behaviors of such macros and functions match requirements.
offsetof
macro that works as expected. The compiler is also free to implementmemmove()
with a comparison that would produce undefined behavior if it was in user code. All do. – Pauiieoffsetof
macro that you can use instead. – Eulogistic