Reputation: 1439
I have an unknown typedef'd numeric type. I'd like to cast it to a size_t
if possible (read: if it fits within the range of a size_t
), otherwise falling through to some error handling code.
Is there a portable way to do so?
Effectively what I'd like to do is:
some_int_type val = <blah>;
if (val < 0 || val > SIZE_MAX) {
// handle error
} else {
return (size_t) val;
}
However, this doesn't work, as val may be signed.
My second thought would be to do this:
if (val < 0 || (unsigned_some_int_type) val > SIZE_MAX) {
// handle error
} else {
return (size_t) val;
}
This would work (I think) - except that I don't have the unsigned version of some_int_type
. I could cast them both to some_int_type
, except that that would not work properly if some_int_type
is smaller than size_t
(and wouldn't work properly if some_int_type
is signed, either, now that I think about it). I could cast them both to uintmax_t
- except that some compilers actually have integer types larger than uintmax_t
. (Notably, __[u]int128
).
So how could I go about doing this?
Upvotes: 0
Views: 102
Reputation: 153456
OP's original code should be fine
some_int_type val = <blah>;
if (val < 0 || val > SIZE_MAX) {
// handle error
} else {
return (size_t) val;
}
OP commented to @Olaf "error: comparison between signed and unsigned integer expressions". Either OP truly saw a warning or has warnings being treated as errors. IAC, it is not a error per C.
If OP is unable to ignore the warning/error, then gently convert to size_t
only as needed. If the unknown type is wider than size_t
, multiplying it by (size_t)1
will not change type and the compare warning should not occur. IAC, the value of val
will not change.
#include <stdint.h>
if (val < 0 || (size_t)1 * val > SIZE_MAX) {
Let the compiler optimize it. Only lesser compilers, could use (size_t)0 + val
.
Further: the message "comparison between signed and unsigned integer expressions" comes up only in select signed integer and unsigned integer compares. It does not come up when the unsigned integer fits in the range of the signed integer type as there would be no problem converting the unsigned integer type to the wider signed integer type.
Upvotes: 1
Reputation: 223872
After checking the negative case, check if the size of the type in question is bigger than a size_t
. If so, cast SIZE_MAX
to type some_int_type
and do the comparison. If not, the value can't be larger than SIZE_MAX
.
if (val < 0) {
// handle error
} else if ((sizeof(some_int_type) > sizeof(size_t)) && (val > (some_int_type)SIZE_MAX)) {
// handle error
} else {
return (size_t) val;
}
Upvotes: 0
Reputation: 1155
Worry about the lack of an unsigned version by pulling it inside the test for positive
if (val >= 0 )
{
if (val <= SIZE_MAX)
{
return (size_t) val;
}
}
// Handle error
return 0;
Upvotes: 0