Reputation: 27425
My header file is
typedef struct vector vector;
vector * vector_create(size_t size);
The c
file:
vector * vector_create(size_t size){
if(size >= PTRDIFF_MAX)
return NULL;
//actual creation logic
}
I need to restrict the size of the vector
to be no more than PTRDIFF_MAX
since I need to subtract pointers to one vector element from the other. The problem comes when I want to test it
void test_create_vector_too_large(void){
#if SIZE_MAX >= PTRDIFF_MAX + 1
list * lst = list_create(((size_t) PTRDIFF_MAX) + 1);
assert(!lst);
#endif
}
This code produce tons of warnings
/home/kjroff/main.c:55:32: warning: integer overflow in preprocessor expression
#if SIZE_MAX >= PTRDIFF_MAX + 1
^
/home/kjroff/main.c:55:29: warning: the right operand of ">=" changes sign when promoted
#if SIZE_MAX >= PTRDIFF_MAX + 1
The intention of the #if
macro was to check if the upper limit of ptrdiff_t
exceeds upper limit of size_t
. In case they are the same this test does not make sense. But it does in case PTRDIFF_MAX < SIZE_MAX
.
How to write such an assertion correctly?
Upvotes: 0
Views: 52
Reputation: 154305
How to write such an assertion correctly?
Instead of
#if SIZE_MAX >= PTRDIFF_MAX + 1
Subtract (SIZE_MAX
is at least 65535) so no overflow possible.
#if SIZE_MAX - 1 >= PTRDIFF_MAX
or simply use >
@pmg
#if SIZE_MAX > PTRDIFF_MAX
Upvotes: 2
Reputation: 223274
The comparison is generally useless, as size_t
and ptrdiff_t
are typically the same width but size_t
is unsigned and ptrdiff_t
is signed, so SIZE_MAX
is necessarily greater than PTRDIFF_MAX
. This is not strictly specified by the C standard, as size_t
is merely the type used for size expressions and is, in spite of intent, not explicitly specified to be sufficient to represent the size of any object. Similarly, ptrdiff_t
is merely the type used for differences of pointers and is, in spite of intent, not explicitly specified to be sufficient to represent the differences of all pointers.
That said, you can change the comparison to SIZE_MAX > PTRDIFF_MAX
, which is equivalent, as pointed out by pmg. Another way to quiet the warnings is to change 1
to 1u
, yielding SIZE_MAX > PTRDIFF_MAX + 1u
. Per C 2018 6.10.1 4, in preprocessing, the integer types behave as if they were intmax_t
and uintmax_t
, so 1u
has the type uintmax_t
, so PTRDIFF_MAX
will be converted to uintmax_t
, then added to 1u
(which will not overflow), and the comparison will be between two uintmax_t
types (avoiding a warning).
The question states “I need to restrict the size of the vector to be no more than PTRDIFF_MAX since I need to subtract pointers to one vector element from the other.” But the unit of a size_t
is one byte, and the unit of a ptrdiff_t
is one array element. Unless the vector
type is a single byte, the result of subtracting two vector *
pointers will be scaled down. Even in constrained systems where size_t
struggles to cover all the possible sizes, ptrdiff_t
should comfortably have room for the differences of two vector *
pointers, regardless of the size of the underlying array. So the test if(size >= PTRDIFF_MAX)
seems useless.
Upvotes: 4