In C an object can be larger than PTRDIFF_MAX, a real possibility in modern 32-bit environments. (Some libc's have been modified to fail malloc invocations that large, but mmap can suffice.) Because pointer subtraction is represented as ptrdiff_t, the expression &a[n] - a could produce undefined behavior where n is > PTRDIFF_MAX. But a + n is well defined behavior for all positive n (signed or unsigned) as long as the size of a is >= n.
There's an asymmetry between pointer-pointer arithmetic and pointer-integer arithmetic; they behave differently and have different semantics. Pointers are a powerful concept, but like most powerful concepts the abstraction can leak and produce aberrations. I realize opinions vary on whether to prefer signed vs unsigned indices and object sizes (IME, the camps tend to split into C vs C++ programers), but the choice shouldn't be predicated on the semantics of C pointers because those semantics alone don't favor one over the other.
Parent* p = container_of(field,Parent,pa_somefield);
access(p->pa_otherfield);
You'd usually define container_of using subtraction (not negative offset per se): #define container_of(FIELD,TYPE,MEMB) ({ \
const typeof( ((TYPE*)0)->MEMB )* _mptr = (FIELD); \
(TYPE*)( (char*)_mptr - __builtin_offsetof(TYPE,MEMB) ); \
})
but you shouldn't actually be using that directly, because thats what the macro is for.
Umm, no? Indices are ordinals[0], forming the canonical/nominal well-ordering of a collection such as a array.
> an ordinal number, or ordinal, is one generalization of the concept of a natural number that is used to describe a way to arrange a (possibly infinite) collection of objects in order, one after another. [...] Ordinal numbers are thus the "labels" needed to arrange collections of objects in order.
0: https://en.wikipedia.org/wiki/Ordinal_number