I have a question about the following simple comparison:
#define BUF_SIZE //maybe large
static char buf[BUF_SIZE];
static char *limit; // some pointer to an element of buf array
void foo(){
if(limit - buf <= sizeof buf){ //<---- This comparison
//...
}
//...
}
Here we are comparing ptrdiff_t
(on the left) which is signed and size_t
(on the right) which is unsigned. The Standard provides the following explanation
6.5.8/3
:
If both of the operands have arithmetic type, the usual arithmetic conversions are performed.
6.3.1.8/1
gives us 3 possibilities:
Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.
Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of the operand with signed integer type.
Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type.
We don't know the conversion rank of ptrdiff_t
and size_t
. Moreover there is no in general a corresponding unsigned type for ptrdiff_t
(unlike, say intptr_t
and uintptr_t
).
QUESTION: Suppose that the conversion rank of ptrdiff_t
is strictly greater than of size_t
and ptrdiff_t
cannot represent all the values of size_t
. What will happen when performing comparison between ptrdiff_t
and size_t
providing that there is no corresponding unsigned integer type for ptrdiff_t
. Is such an implementation even allowed?
If ptrdiff_t
is of greater rank than size_t
and can represent all positive values of size_t
. limit - buf <= sizeof buf
poses no problems then. The compare is done as ptrdiff_t
.
Else ptrdiff_t
may not represent all positive values of size_t
and then the subtraction limit - buf
may be UB per below, so the compare is moot.
J.2 Undefined behavior
The behavior is undefined in the following circumstances:
...
The result of subtracting two pointers is not representable in an object of typeptrdiff_t
(6.5.6).
Is such an implementation even allowed? (conversion rank of
ptrdiff_t
is strictly greater than ofsize_t
andptrdiff_t
cannot represent all the values ofsize_t
)
Yes may be allowed as ptrdiff_t
as long
and size_t
as unsigned
. Both 32-bit. But perhaps not wise.
Note: C17 § 7.19 4 has
Recommended practice
The types used for size_t
and ptrdiff_t
should not have an integer conversion rank greater than that of signed long int
unless the implementation supports objects large enough to make this necessary.
Not that this applies a lot here - just a note.