FUNC(param);
param
什么时候char *
,派人去func_string
。
到的时候int
,派到func_int
我认为可能有一个解决方案,因为变量类型在编译时是已知的..
FUNC(param);
param
什么时候char *
,派人去func_string
。
到的时候int
,派到func_int
我认为可能有一个解决方案,因为变量类型在编译时是已知的..
这在C1X中是可能的,但在当前标准中是不可能的。
它看起来像这样:
#define cbrt(X) _Generic((X), long double: cbrtl, \
default: cbrt, \
float: cbrtf)(X)
编译器知道变量类型,但预处理器不知道(它将代码简单地视为非结构化文本和标记流,并且只对其执行简单的替换操作)。所以恐怕你不能用C宏来实现这一点。
在 C++ 中,他们发明了模板来解决此类问题(以及更多问题)。
您可以测试类型的特征。
例如,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 文档的稍微修改的示例。
在 C89 / ANSI C 中无法运行时检查类型,但 gcc 有一个扩展允许它。如果我记得的话,typeof 或类似的东西。我曾经在 Linux 内核中看到过它。
#define min(x, y) ({ \
typeof(x) _min1 = (x); \
typeof(y) _min2 = (y); \
(void) (&_min1 == &_min2); \
_min1 < _min2 ? _min1 : _min2; })
看看这篇文章: Linux内核中的GCC hacks
当我第一次看到这个时,我实际上在这里问了一个关于 SO 的问题:
我不太确定您将如何使用它来解决您的问题,但值得一看。
你不能用宏来做到这一点。宏的值在编译时被替换并且不被解释。他们只是替代品。
变量类型在编译时确实是已知的,但是宏扩展发生在编译之前。我建议你实现 2 个重载函数而不是宏。
我对泛型的定义:一种结构化的抽象类型,只能用其他具体类型的输入来完全定义
这对我来说听起来就像一个宏
请原谅伪 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;
}