4 ms·
The standard offsetof macro is sometimes defined as: #define offsetof(st, m) ((size_t)(&((st *)0)->m)) That expression has undefined behavior, since it de
by _kst_ 12y ago
The standard offsetof macro is sometimes defined as:
#define offsetof(st, m) ((size_t)(&((st *)0)->m))
That expression has undefined behavior, since it dereferences a null pointer. That doesn't mean it's an invalid definition of offsetof for a given implementation.
Saying that it has "undefined behavior" means that the C language standard says nothing about how it behaves. If its behavior for the current compiler happens to satisfy the language requirements for offsetof, then it's a legitimate implementation. Code that implements the standard library is free to do whatever it likes, as long as the resulting behavior is correct.
Part of the problem, I think, is the way the question is phrased. Quoting the linked article:
> The programmers' community divided into two camps. The first claimed with confidence that it wasn't legal while the others were as sure saying that it was.
The word "legal" doesn't even occur in the C standard. Some program constructs violate constraints or syntax rules; any such violation requires a compile-time diagnostic (which may be a non-fatal error). Other constructs have "undefined behavior"; the standard places no restrictions on what compilers can do for such constructs. Only a `#error` directive actually requires a program to be rejected.
- Taniwha 12y agoto be pedantic the pointer is not being dereferenced (the '&' inhibits that part of the operation)
- _kst_ 12y agoStrictly speaking, yes, it is, at least in the abstract machine. If a unary "&" is applied directly to the result of a unary "" operator, then neither is evaluated. But in this case, the "&" is being applied to "((st )0)->m". "x->y" is syntactic sugar for "(x).y", so this is equivalent to If a unary "&" is applied directly to the result of a unary "" operator, then neither is evaluated. But in this case, the "&" is being applied to "((st )0)->m". "x->y" is syntactic sugar for "(x).y", so this is equivalent to "((st )0)).m)". A compiler will very likely optimize the expression so it doesn't generate machine code to dereference the null pointer. And in fact using this definition for the offsetof macro depends on that optimization, and on the compiler treating a null pointer as address 0.
- userbinator 12y ago> the standard places no restrictions on what compilers can do for such constructs. But it does list some suggestions on what could happen, one of which is "behaving during translation or program execution in a documented manner characteristic of the environment", which is what most C programmers expect of the language. Violating this implicit assumption is what makes compilers user-hostile; choosing the worst possible behaviour, just because the standard does not define it, is never the right thing to do. Related reading: http://blog.metaobject.com/2014/04/cc-osmartass.html http://blog.metaobject.com/2014/04/cc-osmartass.html http://thetrendythings.com/read/7057 http://thetrendythings.com/read/7057 http://blog.regehr.org/archives/1180 http://blog.regehr.org/archives/1180
- _kst_ 12y agoThat suggestion is pretty vague; the only way a compiler could violate it is by not documenting its behavior. The behavior itself can still be completely arbitrary.
- mpweiher 12y agoWell, before the first ANSI standard, ALL behavior was "undefined", and yet we got many working compilers and tons of working code.
- _kst_ 12y agoBefore the first ANSI standard, we had the C Reference Manual in the back of K&R1. The definition was merely less rigorous (and that lack of rigor often led to complex nests of "#ifdef"s). If a compiler generated code that evaluated 2 + 2 and yielded a result of 5, we could confidently say that compiler had a bug.
- monochromatic 12y ago> Saying that it has "undefined behavior" means that the C language standard says nothing about how it behaves. If its behavior for the current compiler happens to satisfy the language requirements for offsetof, then it's a legitimate implementation. Code that implements the standard library is free to do whatever it likes, as long as the resulting behavior is correct. Undefined is not the same as implementation-defined. Yes, a given implementation is free to do whatever it wants, but code that includes a null pointer dereference is not C code.