宏编译的一个问题

laofang 2010-11-02 04:28:09
本问题涉及一些宏的高级用法:字符串化及不定参数宏. 问题在下述测试代码中,请指点.谢谢.

[I][COLOR=#008800]01 [/COLOR][/I] [COLOR=#008080]#include <stdio.h>[/COLOR]
[I][COLOR=#008800]02 [/COLOR][/I] [COLOR=#008080]#include <string.h>[/COLOR]
[I][COLOR=#008800]03 [/COLOR][/I]
[I][COLOR=#008800]04 [/COLOR][/I] [I][COLOR=#008800]/* 除了PR0外,其它宏都有一个ID参数 */[/COLOR][/I]
[COLOR=#f810b0]05 [/COLOR] [COLOR=#008080]#define PR0(str) printf("PR0 Message: %s\n", str)[/COLOR]
[I][COLOR=#008800]06 [/COLOR][/I] [COLOR=#008080]#define PR1(id, ...) printf("PR1 Message" #id ": " __VA_ARGS__)[/COLOR]
[I][COLOR=#008800]07 [/COLOR][/I] [COLOR=#008080]#define PR2(id, str, i, j) printf("PR2 Message" #id ": %s=%d\n", str, i+j)[/COLOR]
[I][COLOR=#008800]08 [/COLOR][/I]
[I][COLOR=#008800]09 [/COLOR][/I] [I][COLOR=#008800]/* 本宏的目的是调用上述各宏,所以需要对PR0区别对待--如果是PR0宏, 调用时不带ID参数.[/COLOR][/I]
[COLOR=#f810b0]10 [/COLOR] [I][COLOR=#008800] * 问题是: 除非将16-20行注释掉,否则无法通过编译, 为什么?[/COLOR][/I]
[I][COLOR=#008800]11 [/COLOR][/I] [I][COLOR=#008800] * 注释掉的这几行代码看起来并无问题,因为下面的测试宏cmp_str 和 call_macro 编译/运行都正常[/COLOR][/I]
[I][COLOR=#008800]12 [/COLOR][/I] [I][COLOR=#008800] */[/COLOR][/I]
[I][COLOR=#008800]13 [/COLOR][/I] [COLOR=#008080]#define CALL_MACRO(macro, id, ...)  \[/COLOR]
[I][COLOR=#008800]14 [/COLOR][/I] [COLOR=#008080]{                                   \[/COLOR]
[COLOR=#f810b0]15 [/COLOR] [COLOR=#008080]    printf("Test " #macro "...\n"); \[/COLOR]
[I][COLOR=#008800]16 [/COLOR][/I] [I][COLOR=#008800]/*  if (0 == strcmp(#macro, "PR0")) \[/COLOR][/I]
[I][COLOR=#008800]17 [/COLOR][/I] [I][COLOR=#008800]    {                               \[/COLOR][/I]
[I][COLOR=#008800]18 [/COLOR][/I] [I][COLOR=#008800]        macro(__VA_ARGS__);         \[/COLOR][/I]
[I][COLOR=#008800]19 [/COLOR][/I] [I][COLOR=#008800]    }                               \[/COLOR][/I]
[COLOR=#f810b0]20 [/COLOR] [I][COLOR=#008800]    else                            \[/COLOR][/I]
[I][COLOR=#008800]21 [/COLOR][/I] [I][COLOR=#008800]*/[/COLOR][/I][COLOR=#008080]  if (1)                          \[/COLOR]
[I][COLOR=#008800]22 [/COLOR][/I] [COLOR=#008080]    {                               \[/COLOR]
[I][COLOR=#008800]23 [/COLOR][/I] [COLOR=#008080]        macro(id, __VA_ARGS__);     \[/COLOR]
[I][COLOR=#008800]24 [/COLOR][/I] [COLOR=#008080]    }                               \[/COLOR]
[COLOR=#f810b0]25 [/COLOR] [COLOR=#008080]}[/COLOR]
[I][COLOR=#008800]26 [/COLOR][/I]
[I][COLOR=#008800]27 [/COLOR][/I] [I][COLOR=#008800]/* verify the stringizing function of macro */[/COLOR][/I]
[I][COLOR=#008800]28 [/COLOR][/I] [COLOR=#008080]#define cmp_str(str)                \[/COLOR]
[I][COLOR=#008800]29 [/COLOR][/I] [COLOR=#008080]{                                   \[/COLOR]
[COLOR=#f810b0]30 [/COLOR] [COLOR=#008080]    if (0 == strcmp(#str, "hi"))    \[/COLOR]
[I][COLOR=#008800]31 [/COLOR][/I] [COLOR=#008080]        printf("Hello!\n");         \[/COLOR]
[I][COLOR=#008800]32 [/COLOR][/I] [COLOR=#008080]    else                            \[/COLOR]
[I][COLOR=#008800]33 [/COLOR][/I] [COLOR=#008080]        printf("Bad passcode!\n");  \[/COLOR]
[I][COLOR=#008800]34 [/COLOR][/I] [COLOR=#008080]}[/COLOR]
[COLOR=#f810b0]35 [/COLOR]
[I][COLOR=#008800]36 [/COLOR][/I] [COLOR=#008080]#define call_macro(macro, id, ...)  \[/COLOR]
[I][COLOR=#008800]37 [/COLOR][/I] [COLOR=#008080]{                                   \[/COLOR]
[I][COLOR=#008800]38 [/COLOR][/I] [COLOR=#008080]    macro(__VA_ARGS__);             \[/COLOR]
[I][COLOR=#008800]39 [/COLOR][/I] [COLOR=#008080]}[/COLOR]
[COLOR=#f810b0]40 [/COLOR]
[I][COLOR=#008800]41 [/COLOR][/I] [B][COLOR=#000080]int[/COLOR][/B] [COLOR=#000000]main[/COLOR]()
[I][COLOR=#008800]42 [/COLOR][/I] [COLOR=#000000]{[/COLOR]
[I][COLOR=#008800]43 [/COLOR][/I]     [COLOR=#000000]CALL_MACRO[/COLOR]([COLOR=#000000]PR1[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#0000ff]1[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#0000ff]"hello %s[/COLOR][COLOR=#0000ff]\n[/COLOR][COLOR=#0000ff]"[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#0000ff]"world"[/COLOR])
[I][COLOR=#008800]44 [/COLOR][/I]     [COLOR=#000000]CALL_MACRO[/COLOR]([COLOR=#000000]PR2[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#0000ff]2[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#0000ff]"total"[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#0000ff]3[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#0000ff]4[/COLOR])
[COLOR=#f810b0]45 [/COLOR] [I][COLOR=#008800]//  CALL_MACRO(PR0, -1, "hi")[/COLOR][/I]
[I][COLOR=#008800]46 [/COLOR][/I]
[I][COLOR=#008800]47 [/COLOR][/I]     [COLOR=#000000]cmp_str[/COLOR]([COLOR=#000000]hi[/COLOR])
[I][COLOR=#008800]48 [/COLOR][/I]     [COLOR=#000000]cmp_str[/COLOR]([COLOR=#000000]hello[/COLOR])
[I][COLOR=#008800]49 [/COLOR][/I]     [COLOR=#000000]call_macro[/COLOR]([COLOR=#000000]PR0[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#000000]-[/COLOR][COLOR=#0000ff]1[/COLOR][COLOR=#000000],[/COLOR] [COLOR=#0000ff]"hello"[/COLOR])
[COLOR=#f810b0]50 [/COLOR]    
[I][COLOR=#008800]51 [/COLOR][/I]     [B][COLOR=#000080]return[/COLOR][/B] [COLOR=#0000ff]0[/COLOR];
[I][COLOR=#008800]52 [/COLOR][/I] [COLOR=#000000]}[/COLOR]
[/FONT]

保留第16-20行代码时的编译错误如下:
test> gcc mm.c
mm.c:44:37: macro "PR2" requires 4 arguments, but only 3 given
mm.c: In function `main':
mm.c:44: error: `PR2' undeclared (first use in this function)
mm.c:44: error: (Each undeclared identifier is reported only once
mm.c:44: error: for each function it appears in.)

另: 用gcc -E进行宏展开时代码没有问题.
...全文
255 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
laofang 2010-11-03
  • 打赏
  • 举报
回复
基于大家的帮助,我最后这样实现:
1.对不带ID的这些宏进行一些封装, 加上ID参数,并在名字后加上一个特殊字串__ID以示区分:
#define PR0__ID(id, str) PR0(str)

2.在CALL_MACRO中进行判断,得到真正的宏名:
#define CALL_MACRO(macro, id, ...) \
{ \
char str[64], *p = NULL; \
strcpy(str, #macro); \
if ((p = strstr(str, "__ID")) != NULL) { \
str[p - str] = '\0'; \
} \
printf("Testing %s with ID=%d...\n", str, id); \
macro(id, __VA_ARGS__); \
printf("Tested.\n\n"); \
}

3.像其它宏一样调用
CALL_MACRO(PR0__ID, 3, "hi")

这样基本上达到了目的,并且避免了重复代码.

谢谢大家的帮助,马上结帖.
laofang 2010-11-02
  • 打赏
  • 举报
回复
谢谢大家的方案,但仍不能满足我的需求.

首先类似PR0这类不带ID参数的宏不只一个, 也有好多个, 所以不能写死.

另外我也不宜修改PR0这个宏去加上一个ID参数, 因为这类不带ID的宏已在现有代码中大量使用,是一个公开的调用接口.

而且,实际的代码并不是上面这样只是做简单的printf输出, ID会作为一个整形值作为数组下标.

谢谢!
yg2362 2010-11-02
  • 打赏
  • 举报
回复
我觉得有个更简单的

#define PR0(str,...) printf("PR0 Message: %s\n", str)
#define PR1(id, ...) printf("PR1 Message" #id ": " __VA_ARGS__)
#define PR2(id, str, i, j) printf("PR2 Message" #id ": %s=%d\n", str, i+j)

#define CALL_MACRO(macro, id, ...) \
macro(id,__VA_ARGS__)

楼主在调用PR0时,将id赋值成输出的字符串就行
selooloo 2010-11-02
  • 打赏
  • 举报
回复
可以这样修改
#define PR0(id,str) printf("PR0 Message: %s\n", str) //加个id参数,但不适用

#define CALL_MACRO(macro, id, ...) \
{ \
printf("Test " #macro "...\n"); \
if (0 == strcmp(#macro, "PR0")) \
{ \
macro(id,__VA_ARGS__); \ //这样形式可以保持一致
} \
else \
if (1) \
{ \
macro(id, __VA_ARGS__); \
} \
}


感觉LZ的需求还是用函数好,宏又不会做形参检查
yg2362 2010-11-02
  • 打赏
  • 举报
回复
你可以这样
#define CALL_MACRO(macro, id, ...) \
{ \
printf("Test " #macro "...\n"); \
if (0 == strcmp(#macro, "PR0")) \
{ \
PR0(__VA_ARGS__); \
} \
else \
{ \
macro(id, __VA_ARGS__); \
} \
}
laofang 2010-11-02
  • 打赏
  • 举报
回复
对呀,我怎么就没想到这点呢!

那有什么办法解决这个问题吗? 难道必须用两个不同的宏才能实现? --实际的代码中在调用宏前后还有很多共用代码, 用两个宏的话就会有不少重复代码.

我再看看...谢谢!
hai040 2010-11-02
  • 打赏
  • 举报
回复
看了小写的了
if (0 == strcmp(#macro, "PR0"))这是运行期的
编译期两个分支都会替换
if (0 == strcmp("PR1", "PR0"))
PR1(....)
else
PR1(...)
hai040 2010-11-02
  • 打赏
  • 举报
回复
macro(__VA_ARGS__);pr1/2是macro(id,__VA_ARGS__);?

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧