13
FUNC(param);

param什么时候char *,派人去func_string

到的时候int,派到func_int

我认为可能有一个解决方案,因为变量类型在编译时是已知的..

4

7 回答 7

16

这在C1X中是可能的,但在当前标准中是不可能的。

它看起来像这样:

#define cbrt(X) _Generic((X), long double: cbrtl, \
                          default: cbrt, \
                          float: cbrtf)(X)
于 2011-08-31T11:24:41.947 回答
11

编译器知道变量类型,但预处理器不知道(它将代码简单地视为非结构化文本和标记流,并且只对其执行简单的替换操作)。所以恐怕你不能用C宏来实现这一点。

在 C++ 中,他们发明了模板来解决此类问题(以及更多问题)。

于 2011-08-31T11:23:50.453 回答
6

您可以测试类型的特征。

例如,int可以保持负值,而char*不能。所以如果((typeof(param))-1) < 0,param是无符号的:

if (((typeof(param))-1) < 0) {
    do_something_with_int();
} else {
    do_something_with_char_p();
}

编译器显然对此进行了优化。

在这里试试:http: //ideone.com/et0v1

如果类型具有不同的大小,这将更容易。例如,如果您想编写一个可以处理不同字符大小的通用宏:

if (sizeof(param) == sizeof(char)) {
    /* ... */
} else if (sizeof(param) == sizeof(char16_t)) {
    /* ... */
} else if (sizeof(param) == sizeof(char32_t)) {
    /* ... */
} else {
   assert("incompatible type" && 0);
}

GCC 有一个__builtin_types_compatible_p()内置函数可以检查类型兼容性:

if (__builtin_types_compatible_p(typeof(param), int)) {
    func_int(param);
} else if (__builtin_types_compatible_p(typeof(param), char*)) {
    func_string(param);
}

在这里试试:http: //ideone.com/lEmYE

你可以把它放在一个宏中来实现你想要做的事情:

#define FUNC(param) ({                                                \
    if (__builtin_types_compatible_p(typeof(param), int)) {           \
        func_int(param);                                              \
    } else if (__builtin_types_compatible_p(typeof(param), char*)) {  \
        func_string(param);                                           \
    }                                                                 \
})

(这({...})是一个GCC 的语句表达式,它允许一组语句是一个右值。

__builtin_choose_expr()内置可以选择要编译的表达式。int使用 __builtin_types_compatible_p 如果参数的类型与两者不兼容,则允许在编译时触发错误char*:(在这种情况下通过编译无效)

#define FUNC(param)                                                        \ 
    __builtin_choose_expr(__builtin_types_compatible_p(typeof(param), int) \ 
        , func_int(param)                                                  \ 
        , __builtin_choose_expr(__builtin_types_compatible_p(typeof(param), char*) \ 
            , func_string(param)                                           \ 
            , /* The void expression results in a compile-time error       \ 
                 when assigning the result to something.  */               \ 
            ((void)0)                                                      \ 
        )                                                                  \ 
    )

这实际上是来自__builtin_choose_expr 文档的稍微修改的示例。

于 2011-08-31T11:48:06.817 回答
4

在 C89 / ANSI C 中无法运行时检查类型,但 gcc 有一个扩展允许它。如果我记得的话,typeof 或类似的东西。我曾经在 Linux 内核中看到过它。

kernel.h 中

#define min(x, y) ({                \
typeof(x) _min1 = (x);          \
typeof(y) _min2 = (y);          \
(void) (&_min1 == &_min2);      \
_min1 < _min2 ? _min1 : _min2; })

看看这篇文章: Linux内核中的GCC hacks

当我第一次看到这个时,我实际上在这里问了一个关于 SO 的问题:

kernel.h 中的 min 宏

我不太确定您将如何使用它来解决您的问题,但值得一看。

于 2011-08-31T11:25:05.283 回答
1

你不能用宏来做到这一点。宏的值在编译时被替换并且不被解释。他们只是替代品。

于 2011-08-31T11:24:20.527 回答
1

变量类型在编译时确实是已知的,但是宏扩展发生在编译之前。我建议你实现 2 个重载函数而不是宏。

于 2011-08-31T11:25:11.150 回答
0

我对泛型的定义:一种结构化的抽象类型,只能用其他具体类型的输入来完全定义

这对我来说听起来就像一个宏

请原谅伪 c 代码,我的 c 生锈了

#include <stdio.h>

// todo: ret=self needs vec3##generic_t##_copy(self, ret);
// not to mention we should probably be using __builtin_add_overflow
// __builtin_add_overflow might actually itself be a reasonably generics method example
// please bear with me
#define GENERIC_VEC3_ADD(generic_t) \
    generic_t vec3##generic_t##_add(generic_t self, generic_t other) {\
        generic_t ret = self;\
        ret[0] += other [0];;\
        ret[1] += other [1];\
        ret[2] += other [2];\
        return ret;\
    }

#define GENERIC_VEC3_FREPR(generic_t, printf_ts) \
    int vec3##generic_t##_frepr(generic_t self, FILE fd)\
        rerurn fprintf(fd, "<vec3##generic_t (##printf_ts##, printf_ts##, printf_ts##)>", \
        self[0], self[1], self[2]);\
    }

// here is the generic typedef, with some methods
#define GENERIC_VEC3(genetic_t, printf_ts) \
    typedef vec3##generic_t generic_t[3];\
    GENERIC_VEC3_ADD(generic_t) \
    GENERIC_VEC3_FREPR(generic_t, printf_ts)

// later we decide what types we want this genic for
GENERIC_VEC3(int, %ul)

// and use our generic
int main()
{
    vec3int foo = { 1, 2, 3 };;
    vec3int bar = { 1, 2, 3 };;
    vec3int sum = vec3int_add(foo, bar);
    vec3int_frepr(sum, stderr);
    fprintf(stderr, "\n");
    exit EXIT_SUCCESS;
}
于 2022-02-10T11:53:37.297 回答