On 02/07/13 15:43, Laszlo Ersek wrote: > On 02/07/13 09:55, Michael S. Tsirkin wrote: >> On Tue, Feb 05, 2013 at 05:47:16PM -0600, Jesse Larrew wrote:
>>> +#define endof(container, field) \ >>> + ((intptr_t)(&(((container *)0)->field)+1)) >> > Furthermore, taking the pointer to "one past" &field, ie. (&field + 1), > is safe, provided &field itself is well-defined. This comes from two > bits in the ISO C standard, sloppily paraphrased: > > - Given an array with N elements, it's allowed to form a pointer to one > past the last element in it. IOW, &array[N], or (array + N), or > (&array[0] + N). You can't dereference it, but the pointer itself is > valid. (C99 6.5.6p8-9.) > > - For the purposes of pointer arithmetic, (&x) works like (&x_array[0]), > where x is an object of type X, outside of an array, and x_array has > element type X and N=1 element. (C99 6.5.6p7.) > > Since you're allowed to evaluate ((&x_array[0]) + 1), you're also > allowed to eval ((&x) + 1). Alas, I was wrong; C99 6.5.6p7 doesn't seem to apply here on a second read, because "x", ie. ((container *)0)->field, is not an existent object here. > Anyway the above expression could be reworked for more portability with > offsetof and sizeof. As-is, it contains a pointer-to-non-void to > intptr_t conversion; what's more, with the resultant integer value meant > to be used numerically later on (ie. not for converting it back to > (void*), C99 7.18.1.4p). (The use of the null pointer is valid, the > dereference is not evaluated because it's the operand of &, C99 > 6.5.2.3p4 and 6.5.3.2p3.) Again, I was too liberal here wrt. the null pointer; the operand of &, ((container*)0)->field, is neither the result of the unary * operator, nor is it "an lvalue that designates an object that [...]". (C99 6.5.3.2p1.) ((container*)0)->field is not an object. > Instead, what about > > #define endof(container, field) \ > (offsetof(container, field) + sizeof ((container *)0)->field) This works nonetheless, because the operand of sizeof is an expression with a non-VLA type, and so it's not evaluated. (C99 6.5.3.4p2.) Sorry for the noise. Laszlo