gpt4 book ai didi

c - 通用求和宏和嵌套宏扩展

转载 作者:行者123 更新时间:2023-11-30 19:31:03 24 4
gpt4 key购买 nike

我使用 C11 _Generic 关键字编写了一个通用求和宏,但在其他通用函数定义中扩展该宏时遇到问题。

这是包含所有辅助宏的总和宏:

// Helper macros
#define _num_map($, _) $(char)_ $(short)_ $(int)_ $(long)_ $(float)_ $(double)
#define _comma ,
#define _gencase(_T, _F) _T: _F(_T)
#define _alen(_xs) sizeof(_xs)/sizeof(_xs[0])
#define _generic(_map, _M, _gen, ...) _Generic((_gen), _map(_M, _comma))(__VA_ARGS__)

// Define sum functions
#define _sum_func(_T) __sum_generic_##_T
#define _def_sum(_T) \
_T _sum_func(_T)(_T *xs, size_t len) \
{ \
_T n = (_T) 0; \
for (size_t i = 0; i < len; i++) \
n += xs[i]; \
return n; \
}
_num_map(_def_sum,)
#undef _def_sum
// Define sum$ and suma$ generic macros:
#define _gen_sum(_T) _gencase(_T, _sum_func)
#define sum$(_xs, _len) _generic(_num_map, _gen_sum, (_xs)[0], _xs, _len)
#define suma$(_xs) sum$(_xs, _alen(_xs))

_num_map使用 是为了避免在函数定义宏和 _Generic 表达式中重复类型。它本质上只是一个列表,具有内置的宏映射,想想 _字符为,$字符是映射的宏。

$ sum$ 末尾的符号和suma$只是一个个人风格指南,意味着“通用宏,如果使用错误,请注意可能出现的奇怪编译器错误/警告。”

这工作得很好,可以像这样使用:

int main(void)
{
int nums[] = {1, 2, 3, 4};
double dubs[] = {1.1, 2.2, 3.3, 4.4};
double dubs0[] = {};
printf("Sum: %d\n", suma$(nums));
printf("DSum: %lf\n", suma$(dubs));
printf("Zero DSum: %lf\n", suma$(dubs0));
return 0;
}

当我尝试做这样的事情时,问题就出现了:

// Define avg functions
#define _avg_func(_T) __avg_generic_##_T
#define _def_avg(_T) \
double _avg_func(_T)(_T *xs, size_t len) \
{ \
return ((double) sum$(xs, len)) / len; \
}
_num_map(_def_avg,)
#undef _def_avg
// Define avg$ and avga$ generic macros:
#define _gen_avg(_T) _gencase(_T, _avg_func)
#define avg$(_xs, _len) _generic(_num_map, _gen_avg, (_xs)[0], _xs, _len)
#define avga$(_xs) avg$(_xs, _alen(_xs))

_num_map(_def_avg,)无法正确扩展,查看 gcc -E sum-generic.c 的输出我可以看到_num_mapsum$ 时被视为函数调用在 _def_avg 内展开。所以出于某种原因gcc不想继续扩张_num_map当它已经扩展时_num_map .

解决问题涉及复制 _num_map :

// Define avg functions
#define _avg_map($, _) $(char)_ $(short)_ $(int)_ $(long)_ $(float)_ $(double)
#define _avg_func(_T) __avg_generic_##_T
#define _def_avg(_T) \
double _avg_func(_T)(_T *xs, size_t len) \
{ \
return ((double) sum$(xs, len)) / len; \
}
_avg_map(_def_avg,)
#undef _def_avg
// Define avg$ and avga$ generic macros:
#define _gen_avg(_T) _gencase(_T, _avg_func)
#define avg$(_xs, _len) _generic(_avg_map, _gen_avg, (_xs)[0], _xs, _len)
#define avga$(_xs) avg$(_xs, _alen(_xs))

我不喜欢这个解决方案有以下三个原因:

  • avg$应该从 sum$ 继承可接受的输入类型列表因为它只支持 sum$ 的类型支持
  • 由于输入类型列表相同,因此我们最终会出现更多代码重复。
  • 具有类似 _num_map 的宏当您只需要“采用数字类型的函数”或者您可以执行类似 _integer_map 的操作时,随处使用的函数非常有用。和_floating_map对于其他类型,这使您可以轻松对类型进行分类。现在您必须复制所有内容,这使得它对于全局分类不太有用。

作弊 #define _avg_map _num_map不起作用,嵌套也不起作用 _num_map更深。

所以我的问题是,有没有办法强制 gcc编译器继续扩展_num_map 里面 _num_map(_def_avg) ?或者我只需要复制 _num_map

最佳答案

不,C 宏永远不会递归。 6.10.3.4 p 2 内容如下:

If the name of the macro being replaced is found during this scan of the replacement list (not including the rest of the source file’s preprocessing tokens), it is not replaced. Furthermore, if any nested replacements encounter the name of the macro being replaced, it is not replaced. These nonreplaced macro name preprocessing tokens are no longer available for further replacement even if they are later (re)examined in contexts in which that macro name preprocessing token would otherwise have been replaced.

关于c - 通用求和宏和嵌套宏扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49598136/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com