C/C++ 种通过宏获得函数名的问题

2020-08-31 14:08:32 +08:00
 Entityless

实在是不知道怎么用一句标题描述这个问题。。

场景如下:

meta.h

#define META_FUNC_NAME(META_TYPE) func_## METY_TYPE
META_FUNC_NAME(SUPPLIED_META_TYPE)() {
	do_something();
}
#undef SUPPLIED_META_TYPE

test.c:

#define SUPPLIED_META_TYPE float
#include "meta.h"

#define SUPPLIED_META_TYPE double
#include "meta.h"

我希望在 test.c 得到 func_doublefunc_float 两个函数。但是,上面的代码最终会展开出两个 func_METY_TYPE 函数:

In file included from test.c:5:
meta.h:1:35: error: redefinition of ‘func_METY_TYPE’
    1 | #define META_FUNC_NAME(META_TYPE) func_## METY_TYPE
      |                                   ^~~~~
meta.h:2:6: note: in expansion of macro ‘META_FUNC_NAME’
    2 | void META_FUNC_NAME(SUPPLIED_META_TYPE)() {
      |      ^~~~~~~~~~~~~~
In file included from test.c:2:
meta.h:1:35: note: previous definition of ‘func_METY_TYPE’ was here
    1 | #define META_FUNC_NAME(META_TYPE) func_## METY_TYPE
      |                                   ^~~~~
meta.h:2:6: note: in expansion of macro ‘META_FUNC_NAME’
    2 | void META_FUNC_NAME(SUPPLIED_META_TYPE)() {
      |      ^~~~~~~~~~~~~~

请问有什么解决方案吗?

2350 次点击
所在节点    C
12 条回复
InkStone
2020-08-31 14:12:21 +08:00
你的##后面不该带空格的吧。

另外,只有 C 需要这么写,C++直接重载就好了
Entityless
2020-08-31 14:20:47 +08:00
@InkStone 因为平台限制只能支持 C,所以想这么写,,
BTW,## 后面加不加空格效果都是一样的
anytk
2020-08-31 14:21:06 +08:00
#define META_FUNC_NAME(meta_type) \
meta_type func_##meta_type(meta_type _arg)

META_FUNC_NAME(float)
{
int x = 1;
}

META_FUNC_NAME(double)
{
int y = 1;
}


这样?
Entityless
2020-08-31 14:23:36 +08:00
// 上文 meta.h 的 META_FUNC_NAME 前面还有个 void
Entityless
2020-08-31 14:28:02 +08:00
@anytk 好像不行
```
In file included from test.c:5:
meta.h:3:45: error: conflicting types for ‘func_SUPPLIED_META_TYPE’
3 | #define META_FUNC_NAME(meta_type) meta_type func_##meta_type(meta_type _arg)
| ^~~~~
meta.h:6:1: note: in expansion of macro ‘META_FUNC_NAME’
6 | META_FUNC_NAME(SUPPLIED_META_TYPE) {
| ^~~~~~~~~~~~~~
In file included from test.c:2:
meta.h:3:45: note: previous definition of ‘func_SUPPLIED_META_TYPE’ was here
3 | #define META_FUNC_NAME(meta_type) meta_type func_##meta_type(meta_type _arg)
| ^~~~~
meta.h:6:1: note: in expansion of macro ‘META_FUNC_NAME’
6 | META_FUNC_NAME(SUPPLIED_META_TYPE) {
| ^~~~~~~~~~~~~~
```
anytk
2020-08-31 14:31:05 +08:00
@Entityless 提供的里面已经没有用 SUPPLIED_META_TYPE 了,宏就是简单的替换。这里做的就是用宏生成函数声明而已,函数体跟在声明后。
wty
2020-08-31 14:36:21 +08:00
```c
#define MergeName1(Name1,Name2) Name1##Name2
#define MergeNames(Name1,Name2) MergeTokens1(Name1,Name2)

#define ChannelFunc_Init MergeNames(INST_NAME, _Init)

#define INST_NAME Channel0

void ChannelFunc_Init(void)
```

我之前这么写的(分布在好几个文件里面,摘抄出来的,顺序可能不对),至于为啥要套两遍我也不知道,试出来的,,,,
pursuer
2020-08-31 14:48:08 +08:00
你写错字了,宏里那个 METY 和参数 META
C 中有##或#的宏参数好像不会嵌套扩展。可以预先把宏扩展一次,像#7 那样
Entityless
2020-08-31 14:48:34 +08:00
@anytk 啊,了解了,谢谢
不过问题的场景是,对于每种 META_TYPE,函数的执行流程都是一摸一样的(类似于 C++ 的模板函数,,
Entityless
2020-08-31 14:50:01 +08:00
@pursuer 哈哈,确实如此,,
Entityless
2020-08-31 14:55:47 +08:00
@wty 神了,正解,阿里嘎多!
codehz
2020-10-05 21:02:19 +08:00
话说 c99 的话,是不是可以试试 https://en.cppreference.com/w/c/language/generic

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/702809

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX