I have a macro that uses GCC\'s typeof to create a variable of the same type of a macro argument. The problem is: if that argument has const
type, the variable crea
You could use a C11 _Generic
selection to map from const
to non-const
type:
#define DECR_(t, x) ({ t y = (x); --y; y; })
#define DECR(x) _Generic((x), \
int: DECR_(int, (x)), \
const int: DECR_(int, (x)), \
long: DECR_(long, (x)), \
const long: DECR_(long, (x)), \
unsigned int: DECR_(unsigned int, (x)), \
const unsigned int: DECR_(unsigned int, (x)), \
long long: DECR_(long long, (x)), \
const long long: DECR_(long long, (x)))
Although it involves a LOT of typing, even if you only need to cover integral types. C11 is also far from being widely available these days. Live example at Coliru.
There is no standard way in c to modify a const variable or remove the specifier from an existing one.
If you don't mind the possible arithmetic promotion you can do this:
#define DECR(x) ({typeof(x + 0) y; y = x; y--; y;})
The trick is that the expression for typeof
is x + 0
, which is a r-value, and so the l-value-constness (which is what you want to avoid) is lost.
The same trick can be done with 1 * x
, but curiously enough, +x
and -x
don't work.
Is it possible to un-const typeof in gcc pure C?
I don't thing so, but this will work:
#define DECR(x) __extension__({__typeof__(x) y = x - 1; y;})
Note that __extension__
is used for disable ISO C forbids braced-groups within expressions[-pedantic]
warning.
This is a rather late answer, but if you don't mind using more GCC extensions you can do this like this (building upon a previous answer somewhat).
#define UNCONST_HAX_(TYPE) ({TYPE _tmp_macro_var_; _tmp_macro_var_;})
#define UNCONST(x) \
__typeof__(_Generic((x), \
signed char: UNCONST_HAX_(signed char), \
const signed char: UNCONST_HAX_(signed char), \
unsigned char: UNCONST_HAX_(unsigned char), \
const unsigned char: UNCONST_HAX_(unsigned char), \
short: UNCONST_HAX_(short), \
const short: UNCONST_HAX_(short), \
unsigned short: UNCONST_HAX_(unsigned short), \
const unsigned short: UNCONST_HAX_(unsigned short), \
int: UNCONST_HAX_(int), \
const int: UNCONST_HAX_(int), \
unsigned: UNCONST_HAX_(unsigned), \
const unsigned: UNCONST_HAX_(unsigned), \
long: UNCONST_HAX_(long), \
const long: UNCONST_HAX_(long), \
unsigned long: UNCONST_HAX_(unsigned long), \
const unsigned long: UNCONST_HAX_(unsigned long), \
long long: UNCONST_HAX_(long long), \
const long long: UNCONST_HAX_(long long), \
unsigned long long: UNCONST_HAX_(unsigned long long), \
const unsigned long long: UNCONST_HAX_(unsigned long long), \
float: UNCONST_HAX_(float), \
const float: UNCONST_HAX_(float), \
double: UNCONST_HAX_(double), \
const double: UNCONST_HAX_(double), \
long double: UNCONST_HAX_(long double), \
const long double: UNCONST_HAX_(long double) \
))
And it could be used as follows:
#define DECR(x) ({UNCONST(x) y; y = x; y--; y;})
Yes, it is pretty ugly.