wzavr 发表于 2016-6-19 15:34:26

从没见识过这么复杂的c语句,实在是看不懂,高手解释下吧

一个例程中看到下面的一段语句,以往的经验实在是看不懂,大概整理了下,例程如下:


=========================================================================

    void print(char x) { printf("%c",x); }
    void print(int x) { printf("%d",x); }
   
#define LogDebug_();
#define LogDebug_1(x) print(x);
#define LogDebug_2(x, args...) print(x); LogDebug_1(args);
#define LogDebug_3(x, args...) print(x); LogDebug_2(args);
#define LogDebug_4(x, args...) print(x); LogDebug_3(args);
#define LogDebug_5(x, args...) print(x); LogDebug_4(args);
#define LogDebug_6(x, args...) print(x); LogDebug_5(args);
#define LogDebug_7(x, args...) print(x); LogDebug_6(args);
#define LogDebug_8(x, args...) print(x); LogDebug_7(args);
#define LogDebug_9(x, args...) print(x); LogDebug_8(args);
#define LogDebug_10(x, args...) print(x); LogDebug_9(args);
#define LogDebug_11(x, args...) print(x); LogDebug_10(args);

#define _NUM_ARGS2(X,X64,X63,X62,X61,X60,X59,X58,X57,X56,X55,X54,X53,X52,X51,X50,X49,X48,X47,X46,X45,X44,X43,X42,X41,X40,X39,X38,X37,X36,X35,X34,X33,X32,X31,X30,X29,X28,X27,X26,X25,X24,X23,X22,X21,X20,X19,X18,X17,X16,X15,X14,X13,X12,X11,X10,X9,X8,X7,X6,X5,X4,X3,X2,X1,N,...) N
#define NUM_ARGS(...) _NUM_ARGS2(0, __VA_ARGS__ ,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)

#define LogDebug_N2(N, args...) LogDebug_ ## N(args)
#define LogDebug_N(N, args...) LogDebug_N2(N, args)
#define LogDebug(args...) do { LogDebug_N(NUM_ARGS(args), args);} while(0)

   
   
void main( void )
{
    int Tmp;
    int DebugData;
    for(Tmp = 0;Tmp < 160; Tmp++)
    {
      DebugData = Tmp;
    }

    for(Tmp = 0;Tmp < 160; Tmp++)
    {
      LogDebug(Tmp, ':', DebugData);
    }

}

=========================================




为了搞清楚,在vc下做了个最简单的dos模板,但是编译也通不过,提示
error C2010: “.”: 宏形参表中的意外
error C2661: “print”: 没有重载函数接受 3 个参数

以为看过的c语言书籍里没有这样的,请高手指点一下。

wzavr 发表于 2016-6-19 15:39:30

比如 LogDebug(150, ':', 200); 语句调用时,实际过程步骤是什么样的呢?

DevLabs 发表于 2016-6-19 15:44:01

关键点应该在__VA_ARGS__这个宏上,你搜索一下看看。

DevLabs 发表于 2016-6-19 15:48:31

你宏只是字符串替换而已,另外你可以搜一下 C语言的可变参数

wzavr 发表于 2016-6-19 15:53:48

本帖最后由 wzavr 于 2016-6-19 15:57 编辑

DevLabs 发表于 2016-6-19 15:44
关键点应该在__VA_ARGS__这个宏上,你搜索一下看看。
__VA_ARGS__简单地搜索看了下,应该还是不难,说是替换 宏定义中参数列表的最后一个参数。
有几步卡壳了,
比如 LogDebug(150, ':', 200);调用,那么经过
#define LogDebug_N2(N, args...) LogDebug_ ## N(args)
#define LogDebug_N(N, args...) LogDebug_N2(N, args)
#define LogDebug(args...) do { LogDebug_N(NUM_ARGS(args), args);} while(0)
的定义转换后,应该是:
LogDebug_150(args)                但是定义里没有 LogDebug_150 啊。

而且定义里的
#define _NUM_ARGS2(X,X64,X63,X62,X61,X60,X59,X58,X57,X56,X55,X54,X53,X52,X51,X50,X49,X48,X47,X46,X45,X44,X43,X42,X41,X40,X39,X38,X37,X36,X35,X34,X33,X32,X31,X30,X29,X28,X27,X26,X25,X24,X23,X22,X21,X20,X19,X18,X17,X16,X15,X14,X13,X12,X11,X10,X9,X8,X7,X6,X5,X4,X3,X2,X1,N,...) N
#define NUM_ARGS(...) _NUM_ARGS2(0, __VA_ARGS__ ,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
彻底晕菜了,那么多数值是怎么用的?

renjun_EMbest 发表于 2016-6-19 15:58:01

关键词:C99 __VA_ARGS__

DevLabs 发表于 2016-6-19 17:01:19

wzavr 发表于 2016-6-19 15:53
__VA_ARGS__简单地搜索看了下,应该还是不难,说是替换 宏定义中参数列表的最后一个参数。
有几步卡壳了 ...

额, 你是怎么看出来
LogDebug(150, ':', 200);
替换为
LogDebug_150(args)
的.....

一步一步来吧, 原始语句:
LogDebug(150, ':', 200);
被这个宏
#define LogDebug(args...) do { LogDebug_N(NUM_ARGS(args), args);} while(0)
替换为:

LogDebug_N(NUM_ARGS(args), args)

显而易见NUM_ARGS()这个宏是用来求参数个数的, 对于你这个语句, 所以它最后将为:

LogDebug_N(3, args)

其中3为NUM_ARGS()这个宏的结果, args仍然是 150, ":", 200.

剩下的你自己替换吧, 很简单的.

在这里说一下这个3是如何求得的.

先看:
#define NUM_ARGS(...) _NUM_ARGS2(0, __VA_ARGS__, 64, 63, ......(略))
可见是一个可变参数宏, 调用了另一个宏.

再看
#define _NUM_ARGS2(X, X64, ....(略), X1, N, ...) N
重点在 N 这里, NUM_ARGS()传给它的参数将会出现在 __VA_ARGS__这里, 在原语句中是3个参数, 所以这里将占用3个位置, 后面的数字依次偏移, 本来N是被替换为0的, 当这3个数字插入后N将被替换为3, 明白了吧? 那多插入了3个参数, _NUM_ARGS2为什么不会出错呢? 因为_NUM_ARGS2()也是可变参数的, 注意末尾的 ...




wzavr 发表于 2016-6-19 18:30:12

DevLabs 发表于 2016-6-19 17:01
额, 你是怎么看出来
LogDebug(150, ':', 200);
替换为


感谢,简介易懂,看明白了宏的替换转变过程。

请教一下一个疑问:
_NUM_ARGS2(X,X64,X63,X62,X61,X60,                这个宏里面用的是X开头的数字,
NUM_ARGS(...) _NUM_ARGS2(0, __VA_ARGS__ ,64,63,62,61,60,59,58,5                这个宏里面直接是数字
有什么区别吗? 意义在哪里?

谢谢。

DevLabs 发表于 2016-6-19 20:13:24

wzavr 发表于 2016-6-19 18:30
感谢,简介易懂,看明白了宏的替换转变过程。

请教一下一个疑问:


一个是宏函数的定义,一个是调用。所以X开头的那些相当于形参,而数字就是实参了。

wzavr 发表于 2016-6-20 08:31:01

DevLabs 发表于 2016-6-19 20:13
一个是宏函数的定义,一个是调用。所以X开头的那些相当于形参,而数字就是实参了。 ...

{:victory:}明白了,谢谢

WM_CH 发表于 2016-6-20 18:06:24

知识贴,顶下。

xiaomu 发表于 2016-6-20 18:31:13

很好,又学到了知识!{:lol:}

huangqi412 发表于 2016-6-20 22:45:28

密密麻麻看的晕

WM_CH 发表于 2016-8-6 00:19:06

本帖最后由 WM_CH 于 2016-8-6 00:20 编辑

楼主是怎么在VS上边试的?我试了一下,报的错跟你的一样。

另外,这是什么的源码。{:smile:}




maimaige 发表于 2016-8-6 07:24:34

mark 好厉害的样子

WM_CH 发表于 2016-8-8 10:33:16

WM_CH 发表于 2016-8-6 00:19
楼主是怎么在VS上边试的?我试了一下,报的错跟你的一样。

另外,这是什么的源码。


楼主,求解答啊

gujiamao_love 发表于 2016-8-9 11:10:02

WM_CH 发表于 2016-8-8 10:33
楼主,求解答啊

...之前加个,

WM_CH 发表于 2016-8-9 12:27:50

gujiamao_love 发表于 2016-8-9 11:10
...之前加个,

谢谢指教。{:biggrin:}

lyz1900 发表于 2016-8-9 14:57:05

这个是不是 GUN C 语法或者 C99 支持的语法,猜测哦,不太清楚,好像这些新标准可以有比较牛掰的用法,vc 是不是不支持,linux 下好像看过这么用的比较多

wzavr 发表于 2016-8-9 15:29:58

WM_CH 发表于 2016-8-6 00:19
楼主是怎么在VS上边试的?我试了一下,报的错跟你的一样。

另外,这是什么的源码。


这个应该是贴子中高手说明的,gnc或者c99的语法,vc中不支持,我上面说过,测试过,无法通过编译.
这段语句也是一个初学的朋友发过来问我的,因为我稍微用过一点c,但是学得太浅薄,也是无法理解,所以发上来请高手帮助的.

WM_CH 发表于 2016-8-9 18:03:39

wzavr 发表于 2016-8-9 15:29
这个应该是贴子中高手说明的,gnc或者c99的语法,vc中不支持,我上面说过,测试过,无法通过编译.
这段语句也 ...

嗯,谢谢。
页: [1]
查看完整版本: 从没见识过这么复杂的c语句,实在是看不懂,高手解释下吧