The SIZE_MAX / 2 limit is determined by the definitions of size_t and ptrdiff_t for your implementation, which select that the types ptrdiff_t and size_t have the same width.
C Standard mandates 1 that type size_t is not specified and type ptrdiff_t is signed.
The result of the difference between the two pointers will always be 2 of type ptrdiff_t. This means that in your implementation, the size of the object must be limited by PTRDIFF_MAX, otherwise the permissible difference between the two pointers cannot be represented in the ptrdiff_t type, which will lead to undefined behavior.
Thus, the value of SIZE_MAX / 2 is equal to the value of PTRDIFF_MAX. If the implementation decides that the maximum size of the object will be SIZE_MAX, then the width of the ptrdiff_t type should be increased. But it is much easier to limit the maximum size of the SIZE_MAX / 2 object, then it must have type ptrdiff_t with a greater or equal positive range than type size_t.
The standard offers these 3 comments 4 per topic.
(Quoted from ISO / IEC 9899: 201x)
1 (7.19 General definitions 2)
Types - ptrdiff_t
which is a recognized integer type of the result of subtracting two pointers; size_t
which is the unsigned integer type of the result of the sizeof operator;
2 (6.5.6 Additive operators 9)
When two pointers are subtracted, both must point to the elements of the same array object, or one after the last element of the array object; as a result, there is a difference in the indices of the two elements of the array. The size of the result is determined by the implementation, and its type (signed integer type) is ptrdiff_t defined in the header. If the result is not represented in an object of this type, the behavior is undefined.
3 (K.3.4 Integer types 3)
Extremely large sizes of objects are often a sign that the size of the object was calculated incorrectly. For example, negative numbers appear as very large positive numbers when converted to an unsigned type of type size_t. In addition, some implementations do not support objects whose maximum values ββcan be represented by size_t.
4 (K.3.4 Integer types 4)
For these reasons, it is sometimes useful to limit the size range of objects to detect programming errors. For implementations oriented to machines with large address spaces, it is recommended that RSIZE_MAX be defined as the smaller size of the largest object (or SIZE_MAX β 1), even if this limit is less than the size of some legitimate but very large objects. Implementations targeting machines with small address spaces may wish to define RSIZE_MAX as SIZE_MAX, which means that there is no object size that is considered a violation of the run-time limit.