'Is it possible to un-const typeof in gcc pure C?
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 created inside the macro is const and I can't use it. For instance:
#include <stdio.h>
#define DECR(x) ({typeof(x) y; y = x; y--; y;})
int main(void)
{
const int v = 5;
printf("%d\n", DECR(v));
return 0;
}
Compilation gives:
$ cc -c -o t.o t.c
t.c: In function 'main':
t.c:9:2: error: assignment of read-only variable 'y'
t.c:9:2: error: decrement of read-only variable 'y'
make: *** [t.o] Error 1
Is there a way to copy the typeof a value and un-const it?
Solution 1:[1]
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.
Solution 2:[2]
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.
Solution 3:[3]
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.
Solution 4:[4]
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.
Solution 5:[5]
__auto_type will remove const and volitale.
Like this:
#include <stdio.h>
int main()
{
const int x=3;
__typeof__(({__auto_type y=x; y;})) z=1;
z++;
printf("%d %d\n", x, z);
return 0;
}
You can change your code to:
#define __auto_typeof(x) __typeof__(({__auto_type y=x; y;}))
#include <stdio.h>
#define DECR(x) ({__auto_typeof(x) y; y = x; y--; y;})
int main(void)
{
const int v = 5;
printf("%d\n", DECR(v));
return 0;
}
Solution 6:[6]
There is no standard way in c to modify a const variable or remove the specifier from an existing one.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | rodrigo |
| Solution 2 | |
| Solution 3 | Casey |
| Solution 4 | |
| Solution 5 | untitled |
| Solution 6 |
