搜索
bottom↓
回复: 20

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

[复制链接]

出0入0汤圆

发表于 2016-6-19 15:34:26 | 显示全部楼层 |阅读模式
一个例程中看到下面的一段语句,以往的经验实在是看不懂,大概整理了下,例程如下:


  1. =========================================================================

  2.     void print(char x) { printf("%c",x); }
  3.     void print(int x) { printf("%d",x); }
  4.    
  5. #define LogDebug_();
  6. #define LogDebug_1(x) print(x);
  7. #define LogDebug_2(x, args...) print(x); LogDebug_1(args);
  8. #define LogDebug_3(x, args...) print(x); LogDebug_2(args);
  9. #define LogDebug_4(x, args...) print(x); LogDebug_3(args);
  10. #define LogDebug_5(x, args...) print(x); LogDebug_4(args);
  11. #define LogDebug_6(x, args...) print(x); LogDebug_5(args);
  12. #define LogDebug_7(x, args...) print(x); LogDebug_6(args);
  13. #define LogDebug_8(x, args...) print(x); LogDebug_7(args);
  14. #define LogDebug_9(x, args...) print(x); LogDebug_8(args);
  15. #define LogDebug_10(x, args...) print(x); LogDebug_9(args);
  16. #define LogDebug_11(x, args...) print(x); LogDebug_10(args);

  17. #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
  18. #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)

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

  22.    
  23.    
  24. void main( void )
  25. {
  26.     int Tmp;
  27.     int DebugData[160];
  28.     for(Tmp = 0;Tmp < 160; Tmp++)
  29.     {
  30.         DebugData[Tmp] = Tmp;
  31.     }

  32.     for(Tmp = 0;Tmp < 160; Tmp++)
  33.     {
  34.         LogDebug(Tmp, ':', DebugData[Tmp]);
  35.     }

  36. }

  37. =========================================
复制代码




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

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

出0入0汤圆

 楼主| 发表于 2016-6-19 15:39:30 | 显示全部楼层
比如 LogDebug(150, ':', 200); 语句调用时,实际过程步骤是什么样的呢?

出0入0汤圆

发表于 2016-6-19 15:44:01 来自手机 | 显示全部楼层
关键点应该在__VA_ARGS__这个宏上,你搜索一下看看。

出0入0汤圆

发表于 2016-6-19 15:48:31 来自手机 | 显示全部楼层
你宏只是字符串替换而已,另外你可以搜一下 C语言的可变参数

出0入0汤圆

 楼主| 发表于 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)
彻底晕菜了,那么多数值是怎么用的?

出0入0汤圆

发表于 2016-6-19 15:58:01 | 显示全部楼层
关键词:C99 __VA_ARGS__

出0入0汤圆

发表于 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()也是可变参数的, 注意末尾的 ...




出0入0汤圆

 楼主| 发表于 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                这个宏里面直接是数字
有什么区别吗? 意义在哪里?

谢谢。

出0入0汤圆

发表于 2016-6-19 20:13:24 来自手机 | 显示全部楼层
wzavr 发表于 2016-6-19 18:30
感谢,简介易懂,看明白了宏的替换转变过程。

请教一下一个疑问:

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

出0入0汤圆

 楼主| 发表于 2016-6-20 08:31:01 | 显示全部楼层
DevLabs 发表于 2016-6-19 20:13
一个是宏函数的定义,一个是调用。所以X开头的那些相当于形参,而数字就是实参了。 ...

明白了,谢谢

出0入0汤圆

发表于 2016-6-20 18:06:24 | 显示全部楼层
知识贴,顶下。

出0入0汤圆

发表于 2016-6-20 18:31:13 | 显示全部楼层
很好,又学到了知识!

出0入0汤圆

发表于 2016-6-20 22:45:28 来自手机 | 显示全部楼层
密密麻麻看的晕

出0入0汤圆

发表于 2016-8-6 00:19:06 | 显示全部楼层
本帖最后由 WM_CH 于 2016-8-6 00:20 编辑

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

另外,这是什么的源码。




出0入0汤圆

发表于 2016-8-6 07:24:34 | 显示全部楼层
mark 好厉害的样子

出0入0汤圆

发表于 2016-8-8 10:33:16 | 显示全部楼层
WM_CH 发表于 2016-8-6 00:19
楼主是怎么在VS上边试的?我试了一下,报的错跟你的一样。

另外,这是什么的源码。

楼主,求解答啊

出0入0汤圆

发表于 2016-8-9 11:10:02 | 显示全部楼层
WM_CH 发表于 2016-8-8 10:33
楼主,求解答啊

...之前加个,

出0入0汤圆

发表于 2016-8-9 12:27:50 | 显示全部楼层

谢谢指教。

出0入0汤圆

发表于 2016-8-9 14:57:05 | 显示全部楼层
这个是不是 GUN C 语法或者 C99 支持的语法,猜测哦,不太清楚,好像这些新标准可以有比较牛掰的用法,vc 是不是不支持,linux 下好像看过这么用的比较多

出0入0汤圆

 楼主| 发表于 2016-8-9 15:29:58 | 显示全部楼层
WM_CH 发表于 2016-8-6 00:19
楼主是怎么在VS上边试的?我试了一下,报的错跟你的一样。

另外,这是什么的源码。

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

出0入0汤圆

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

嗯,谢谢。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-19 21:23

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表