Is it guaranteed by the C standard that, given type_t* x = NULL; type_t* y = NULL; we always have x > y evaluating as false? I ask because of the conversation in initial or terminal malloc buffer possible? from which it seems that one should be careful with pointer comparison, and only compare when one is dealing with pointers to elements of the same array, loosely speaking. However, it is convenient to have x > y evaluating as false guaranteed, because I want a struct which is an stack-ish array having fields for the first and post-last elements, and if this array still has 0 elements, it is convenient to set these fields to be NULL, and it is convenient to still allow for for looping over elements of the array, without checking explicitly whether the array has 0 elements or more, so such a comparison is handy...
1 Answer
Surprisingly, in C it appears to cause undefined behavior. Only == and != can work with null pointers. The workaround is to cast the pointers to uintptr_t and compare the results.
C17 6.5.8 Relational operators /5
When two pointers are compared, the result depends on the relative locations in the address space of the objects pointed to. If two pointers to object types both point to the same object, or both point one past the last element of the same array object, they compare equal. If the objects pointed to are members of the same aggregate object, pointers to structure members declared later compare greater than pointers to members declared earlier in the structure, and pointers to array elements with larger subscript values compare greater than pointers to elements of the same array with lower subscript values. All pointers to members of the same union object compare equal. If the expression P points to an element of an array object and the expression Q points to the last element of the same array object, the pointer expression Q+1 compares greater than P. In all other cases, the behavior is undefined.
(bold mine)
This is unlike C++, where there's a clause explicitly saying that <,<=,>,>= are consistent with ==,!=:
If two operands
pandqcompare equal ([expr.eq]),p<=qandp>=qboth yieldtrueandp<qandp>qboth yieldfalse. ...
9 Comments
NULL is a pointer type. It can be integral and then false is guaranteed. And in C++, as well as presumably C23, it may also fail to compile, if NULL is of type nullptr_t.NULLs directly. OP most likely means that they have pointer variables they assign NULL to.NULL to.NULL > NULL would, according to this answer, only be undefined if the implementation made the implementation-defined choice to use (void*)0 (or similar) as definition of NULL.
NULL > NULLas an expression is guaranteed to evaluate tofalseor whether you want to ask whetherX > Ywhere bothXandYare null pointer values (of the same type) is guaranteed to evaluate tofalse. These are quite different questions. (In particular,NULLis not a null pointer value in general, but a null pointer constant instead.)