C语言 define
宏字符串拼接
标记粘贴运算符(##)
宏定义内的标记粘贴运算符(##)会合并两个参数。它允许在宏定义中两个独立的标记被合并为一个标记。例如:
1 | #include <stdio.h> |
结果
1 | token34 = 40 |
我们偶尔会在代码里看到这样的用法:
1 | int Flower = 1; |
三个函数在其他地方有调用,find一下声明又find不到。找来找去找到个类似声明的写法:
1 | DeclareGetNameId(Flower); |
其宏函数的定义有可能是长这样的:
1 |
宏定义中,##表示字符串拼接,一般用于消除大面积的结构性重复比如上面的例子。
什么?你想把函数定义里的重复也消掉?也可以:
1 |
|
这段代码还有重复,好吧定义里有一行可以直接用声明替换,再改改:
1 |
什么?调用点也想用这种花里胡哨的方法?行,给你一个:
1 |
又重复了,好吧调用点用的宏和声明用的宏里面Get##name##Id出现了两次,看来得为这个东西单独写个宏了:
1 |
上面这段代码可以作为你的工具库,走到哪儿带到哪儿。什么?名字不通用?同时你还想返回别的类型?好吧我们改改:
1 |
这段代码已经做了非常多的消除重复的动作,终于可以作为程序员必备了吧?
下面我们验证一下。使用gcc -E x.c可以生成预处理文件,也就是把宏展开后生成一个文件,默认打在terminal,通过gcc -E x.c > x.i打印到x.i里,代码如下:
1 | DeclareGetNameInst(int, Flower); |
展开如下:
1 | int GetFlower(); |
下面我们总结一下这个写法的优缺点:优点已经体现得比较清楚了,代码整洁,重复度低;缺点在本文开头也说过了,无法通过IDE的find定义、声明、调用功能进行代码阅读,代码阅读是无法流畅的。
下面谈一下具体工作中应该怎么选:宏函数这个东西,能不用则不用,毕竟安全性不太行。但凡事有个例外,假如3个同质函数可以忍,30个300个呢?太多就用吧。
延伸阅读(例子来源于多个帖子):
我们已经知道了##是用来进行拼接的。下面还有几个小知识点:
1、#表示字符串替换。网上常见的例子是这样
1 |
example(abc);展开之后:
1 | printf("the input string is:\t%s\n","abc"); |
2、#@表示字符替换。看两个小例子:
1 |
char a = ToChar(1);结果就是a=’1’;
char* str = ToString(123132);就成了str=”123132”;
宏定义。字符串拼接和字符串整形转字符串
样例
1 |
|
C语言 define 定义函数(多行书写)
- 待整理
C 语言:条件编译(#if,#ifdef,#ifndef,#endif,#else,#elif)
- [C语言条件编译(#if,#ifdef,#ifndef,#endif,#else,#elif)](https://c.biancheng.net/view/449.html)
指令 描述 #define 定义宏 #defined defined 可以出现在 #if 或 #elif 命令的条件中 #include 包含一个源代码文件 #undef 取消已定义的宏 #ifdef [测试某个宏是否已被定义]如果宏已经定义,则返回真 #ifndef [测试某个宏是否已被定义]如果宏没有定义,则返回真 #if 如果给定条件为真,则编译下面代码 #else #if 的替代方案 #elif 如果前面的 #if 给定条件不为真,当前条件为真,则编译下面代码 #endif 结束一个 #if……#else 条件编译块 #error 当遇到标准错误时,输出错误消息 #pragma 使用标准化方法,向编译器发布特殊的命令到编译器中
defined 运算符
defined 运算符相对于 #ifdef 和 #ifndef 命令的优点是:你可以在更大型的预处理器表达式中使用它的值。如下例所示:
1 |
|
- 大多数编译器会提供预定义宏,例如上例所使用的宏,它用来识别目标系统和编译器。因此,在 Unix 系统中,通常预先定义好了宏 __unix__,而 GCC 编译器则会预先定义好了宏 __GNUC__。类似地,微软 Windows 平台上的 Visual C 编译器会自动定义好宏 _WIN32 和宏 _MSC_VER。
条件编译
- #if、#ifdef 或 #ifndef 等命令作为开头
1 | #if 表达式1 |
- 预处理器会依次计算条件表达式,直到发现结果非 0(也就是 true)的条件表达式。预处理器会保留对应组内的源代码,以供后续处理。如果找不到值为 true 的表达式,并且该条件式编译区域中包含 #else 命令,则保留 #else 命令组内的代码。
参数化的宏
CPP 一个强大的功能是可以使用参数化的宏来模拟函数。例如,下面的代码是计算一个数的平方:
1 | int square(int x) { |
我们可以使用宏重写上面的代码,如下:
1 | #define square(x) ((x) * (x)) |
在使用带有参数的宏之前,必须使用 #define 指令定义。参数列表是括在圆括号内,且必须紧跟在宏名称的后边。宏名称和左圆括号之间不允许有空格。例如:
实例
1 | #include <stdio.h> |
当上面的代码被编译和执行时,它会产生下列结果:
1 | Max between 20 and 10 is 20 |