Reputation: 7345
From ISO/IEC 9899:2024, 6.2.5 Types:
... 5 A bit-precise signed integer type is designated as
_BitInt(N)
where N is an integer constant expression that specifies the number of bits that are used to represent the type, including the sign bit. Each value ofN
designates a distinct type. (30)
where the footnote states:
- Thus,
_BitInt(3)
is not the same type as_BitInt(4)
.
So I put together this code:
#include <assert.h>
#define IS_SIGNED(T) \
_Generic((T), \
_BitInt: 1, \
default: 0 \
)
#define IS_UNSIGNED(T) \
_Generic((T), \
unsigned _BitInt: 1, \
default : 0 \
)
int main(void)
{
_BitInt(10) ten_bits = 0;
_BitInt(5) five_bits = 0;
unsigned _BitInt(2) two_bits = 0;
unsigned _BitInt(8) eight_bits = 0;
assert(IS_SIGNED(ten_bits));
assert(!IS_SIGNED(five_bits));
assert(IS_UNSIGNED(two_bits));
assert(!IS_UNSIGNED(eight_bits));
}
which did not compile, of course, because _BitInt
is meaningless by itself, and requires an integer constant expression between parenthesis. Changing the cases in _Generic
to:
_BitInt(10): 1,
and:
unsigned _BitInt(2): 1,
sure worked. Now is there a way I can determine whether an expression has type _BitInt(N)
or type unsigned _BitInt(N)
where N
is any integer constant expression without having separate cases from 2 to BITINT_MAXWIDTH
?
Upvotes: 1
Views: 144
Reputation: 214770
I don't think you can do this with _Generic
. A compromise might be to do something like this instead:
#define IS_SIGNED(T) ( ~(typeof(T)){} < 0)
#define IS_UNSIGNED(T) ( ~(typeof(T)){} >= 0)
This creates a compound literal of the same type as T (which may be _BitInt
or some other integer type), initializes it to zero and does a bitwise inverse. Since the operand 0
of the comparison operators is of type int
, there may be an integer promotion of the operand containing the compound literal. However, in case it was signed it will still be negative and the sign is preserved and in case it was unsigned, it will remain a positive value after promotion.
The down side is that this isn't really type safe. You could pass a large integer type, a float type or a pointer and then the macro could fail.
Upvotes: 2