高手帮忙解读复杂宏定义(#define)用法,实在看不懂!!

ranqingfa 2015-10-31 10:17:58
其实是在看开源飞控apm的代码时候看到的,代码是基于C和C++的,

#define GSCALAR(v, name, def) { g.v.vtype, name, Parameters::k_param_ ## v, &g.v, {def_value : def} }

具体使用时这样的:

const AP_Param::Info Copter::var_info[] = {
// @Param: SYSID_SW_MREV
// @DisplayName: Eeprom format version number
// @Description: This value is incremented when changes are made to the eeprom format
// @User: Advanced
GSCALAR(format_version, "SYSID_SW_MREV", 0),

。。。
}

还请高人帮忙解读,看的脑仁疼啊,本人C是初级水平,对这种复杂宏定义实在不懂!
...全文
521 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
ranqingfa 2015-11-07
  • 打赏
  • 举报
回复
引用 8 楼 ForestDB 的回复:
gcc -E input cpp input 直接看宏展开的结果
不太懂啊?就是说在命令行输入上述指令? 小白,抱歉
赵4老师 2015-11-02
  • 打赏
  • 举报
回复
#与##在宏定义中的--宏展开
#include <stdio.h>
#define f(a,b) a##b
#define g(a)   #a
#define h(a) g(a)
int main()
{
        printf("%s\n", h(f(1,2)));   // 12
        printf("%s\n", g(f(1,2))); // f(1,2)
        return 0;
}
宏展开时:
如果宏定义以#开头,不展开参数,直接替换。
故g(f(1,2))--->#f(1,2)--->"f(1,2)";
如果宏定义不以#开头,展开参数,直接替换,由外层向里层,如果碰到的是#开头的宏,不继续往里层展开,往外层展开。
由外层向里层,如果碰到的是以非#开头的宏,继续往里层走,直至最里层,开始一层层往外层展开。
故h(f(1,2))--->h(12)--->g(12)---->#12----->"12"。
PS:
##在宏中定义,是字符连接符
如a##b##c 等同于 "abc"
#在宏开头出现,是表示宏展开的方式不同
#a 等同于"a"
#abc 等同于 "abc"
复杂的:
#include <stdio.h>
#define f(a,b) a##b
#define g(a)   #a
#define h(a) g(a)
int main()
{
        char a = 'a';
        cout<<g(a)<<endl; // a
        cout<<g(g(a))<<endl; // a
        printf("%s\n", h(f(1,2)));   // 12
        printf("%s\n", g(f(1,2))); // f(1,2)
        printf("%s\n", g(h(f(1,2)))); // h(f(1,2))
        printf("%s\n", h(g(f(1,2)))); // "f(1,2)"
        printf("%s\n", h(h(f(1,2)))); // "12"
        system("pause");
        return 0;
}
预处理后的:(在编译选项中添加/EP /P后编译生成的.i文件。gcc加-E)
int main()
{
        char a = 'a';
        cout<<"a"<<endl;
        cout<<"g(a)"<<endl;
        printf("%s\n", "12");
        printf("%s\n", "f(1,2)");
        printf("%s\n", "h(f(1,2))");
        printf("%s\n", "\"f(1,2)\"");
        printf("%s\n", "\"12\"");
        system("pause");
        return 0;
}
---------------------------------------------------
宏解析
1.       ##操作符
##操作符它的作用是在替代表中将其前后的参数连接成为一个预处理符号,它不能出现于宏替代表的开端和末尾。
例:
#define concat(s,t) s##t
#define AAA ABC
concat(A, AA)
将被替换成
ABC
2.       重新扫描和替换
在替换列表中的所有参数替换过之后,预处理器将对结果token序列重新扫描以便对其中的宏再次替换。
当正在替换的宏在其替换列表中发现自身时,就不再对其进行替换。在任何正在嵌套替换的宏的替换过程中遇到正被替换的宏就对其不再进行替换(防止递归)。
例:
#define ROOT AAA CCC
#define AAA ROOT
ROOT
将被替换成
ROOT CCC
ForestDB 2015-11-02
  • 打赏
  • 举报
回复
gcc -E input cpp input 直接看宏展开的结果
ranqingfa 2015-11-02
  • 打赏
  • 举报
回复
引用 1 楼 fefe82 的回复:
宏展开基本就是文本替换。 ## 的作用是连接前后两个符号。 #define GSCALAR(v, name, def) { g.v.vtype, name, Parameters::k_param_ ## v, &g.v, {def_value : def} } GSCALAR(format_version, "SYSID_SW_MREV", 0) 展开时就是将 { g.v.vtype, name, Parameters::k_param_ ## v, &g.v, {def_value : def} } 里的符号做如下替换: v --> format_version name --> "SYSID_SW_MREV" def --> 0 然后把 ## 两侧的符号连接在一起 { g.format_verion.vtype, "SYSID_SW_MREV", Parameters::k_param_format_version, &g.format_version, {def_value : 0} }
就是简单的替换?我还以为很负责的函数用法呢
ranqingfa 2015-11-02
  • 打赏
  • 举报
回复
引用 1 楼 fefe82 的回复:
宏展开基本就是文本替换。 ## 的作用是连接前后两个符号。 #define GSCALAR(v, name, def) { g.v.vtype, name, Parameters::k_param_ ## v, &g.v, {def_value : def} } GSCALAR(format_version, "SYSID_SW_MREV", 0) 展开时就是将 { g.v.vtype, name, Parameters::k_param_ ## v, &g.v, {def_value : def} } 里的符号做如下替换: v --> format_version name --> "SYSID_SW_MREV" def --> 0 然后把 ## 两侧的符号连接在一起 { g.format_verion.vtype, "SYSID_SW_MREV", Parameters::k_param_format_version, &g.format_version, {def_value : 0} }
就是简单的替换?我还以为很负责的函数用法呢
ranqingfa 2015-11-02
  • 打赏
  • 举报
回复
引用 1 楼 fefe82 的回复:
宏展开基本就是文本替换。 ## 的作用是连接前后两个符号。 #define GSCALAR(v, name, def) { g.v.vtype, name, Parameters::k_param_ ## v, &g.v, {def_value : def} } GSCALAR(format_version, "SYSID_SW_MREV", 0) 展开时就是将 { g.v.vtype, name, Parameters::k_param_ ## v, &g.v, {def_value : def} } 里的符号做如下替换: v --> format_version name --> "SYSID_SW_MREV" def --> 0 然后把 ## 两侧的符号连接在一起 { g.format_verion.vtype, "SYSID_SW_MREV", Parameters::k_param_format_version, &g.format_version, {def_value : 0} }
就是简单的替换?我还以为很负责的函数用法呢
weixin_32338547 2015-11-01
  • 打赏
  • 举报
回复
name和def前面没有##应该没有被替换到吧
fefe82 2015-11-01
  • 打赏
  • 举报
回复
引用 2 楼 weixin_32338547 的回复:
name和def前面没有##应该没有被替换到吧
## 是用来连接两侧的符号的,不影响替换。
fefe82 2015-10-31
  • 打赏
  • 举报
回复
宏展开基本就是文本替换。 ## 的作用是连接前后两个符号。 #define GSCALAR(v, name, def) { g.v.vtype, name, Parameters::k_param_ ## v, &g.v, {def_value : def} } GSCALAR(format_version, "SYSID_SW_MREV", 0) 展开时就是将 { g.v.vtype, name, Parameters::k_param_ ## v, &g.v, {def_value : def} } 里的符号做如下替换: v --> format_version name --> "SYSID_SW_MREV" def --> 0 然后把 ## 两侧的符号连接在一起 { g.format_verion.vtype, "SYSID_SW_MREV", Parameters::k_param_format_version, &g.format_version, {def_value : 0} }
1) 本套课程针对高校大学生系统学习C语言而录制,从0基础入门讲起,循序渐进,通俗易懂,同时适用于计算机系及非计算机系的同学。通过学习可以帮助大家掌握C语言本质,轻松面对C语言全国二级考试,并达到能独立完成中型C项目、C游戏的水平;2) 多数高校都开设了C语言课程,网上C语言课程也很多,但普遍存在两个问题: (1) 授课方式单一,大多是照着代码念一遍, 对刚刚接触编程的同学来说,感觉晦涩难懂 (2) 授课内容过度注重语法,没有项目实战支撑,造成课程枯燥无趣。本课程针对上述问题进行了改进 (1) 授课方式采用语法讲解+内存布局示意图+项目的方式,让课程生动有趣好理解 (2) 系统全面的讲解了C语言的核心技术点,还配套录制了《全国计算机二级C语言真题精讲》,让学员在掌握C语言编程的同时,还能轻松面对二级考试;3) 课程详细内容: 常量-变量、分支语句、循环语句、操作符和表达式、函数(库函数、自定义函数、递归调用 )、数组(一维数 组、二维数组、数组作为函数参数、指针数组)、指针(指针和指针类型、二级指针和多级指针、指针表达式解析、指针运算、数 组指针、函数指针、回调函数)、调试技巧、程序环境和预处理(翻译环境、运行环境、预定义符号、#define和#undef、宏和函 数、条件编译、文件包含)、 数据在内存中的存储、内存块分配、static、字符函数和字符串函数、自定义类型(结构体、枚举 、联合)、动态内存管理、文件操作(i/o常量、i/o函数、流)。

33,311

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 新手乐园
社区管理员
  • 新手乐园社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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