'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