13

我有一个宏,它使用 GCC 的 typeof 创建一个与宏参数类型相同的变量。问题是:如果该参数具有const类型,则在宏中创建的变量是const并且我不能使用它。例如:

#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;
}

编译给出:

$ 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

有没有办法复制一个值的类型并取消它?

4

5 回答 5

10

如果您不介意可能的算术提升,您可以这样做:

#define DECR(x) ({typeof(x + 0) y; y = x; y--; y;})

诀窍是 is 的表达式typeofx + 0它是一个 r 值,因此 l-value-constness (这是你想要避免的)丢失了。

同样的技巧可以用 来完成1 * x,但奇怪的是,+x-x不起作用。

于 2013-08-05T21:08:21.553 回答
4

这是一个相当晚的答案,但如果您不介意使用更多 GCC 扩展,您可以这样做(在某种程度上基于先前的答案)。

#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)         \
    ))

它可以按如下方式使用:

#define DECR(x) ({UNCONST(x) y; y = x; y--; y;})

是的,它非常丑陋。

于 2019-01-03T05:17:17.753 回答
3

您可以使用 C11_Generic选择从映射const到非const类型:

#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)))

尽管它涉及很多类型,即使您只需要涵盖整数类型。如今,C11 也远未广泛使用。Coliru 的活生生的例子。

于 2013-08-05T18:11:22.667 回答
2

是否可以在 gcc 纯 C 中取消 const typeof?

我不这么认为,但这会起作用:

#define DECR(x) __extension__({__typeof__(x) y = x - 1; y;})

请注意,__extension__用于禁用ISO C forbids braced-groups within expressions[-pedantic]警告。

于 2013-08-05T17:22:22.593 回答
-1

c中没有标准方法来修改 const 变量或从现有变量中删除说明符。

于 2013-08-05T17:10:56.983 回答