关于宏的一些知识¶
- 定义带参宏时,需要注意必须确保宏名称与左括号之间没有空白符,如果在名称后面有任何空白,那么命令就会把宏作为没有参数的宏处理
- 宏可以嵌套使用,但是不能递归使用
- 无法再次使用
#defien命令重新定义一个已经被定义为宏的标识符,除非重新定义的替换文本与已经被定义的替换文本完全相同。如果想改变一个宏的内容,必须使用下面的命令取消现在的定义#undef 宏名称 - 宏定义和常量定义之间的区别
共同之处:一改全改,避免输入错误
不同之处:
- 宏定义是在编译之前,即预处理阶段展开的,而const是在预编译阶段进行的
- #defien 宏没有类型,不做任何类型检查,仅仅是展开;但是const常量有具体的类型,在编译阶段会执行类型检查
- #defien 宏仅仅是展开,有多少地方使用,就会进行宏展开多少次,不会分配内存。const定义常量会分配内存
备注:
1. C语言编译:C语言编译的过程就是把我们可以理解的高级语言代码转换为计算机可以识别的机器代码的过程
2. 编译主要包括的过程有:预编译;编译;汇编;链接
3. 预编译:删除所有注释;宏展开;文件包含(通过#include来实现)
4. 编译:通过编译器软件一次性对程序代码解析(语法分析),并通过终端窗口来提示源代码中存在的语法错误或警告
5. 汇编:使用汇编程序将程序集级代码(即由编译产生的.s文件)转换为机器可以理解的代码(二进制/十六进制形式)
6. 链接:链接是将库文件包含在我们的程序中的过程。库文件是一些预定义文件,其中包含机器语言中的函数定义,这些文件的扩展名为.lib
可以使用#来将宏对应的宏参数转换为字符串形式。
- 使用带参宏时,建议在替换文本中的参数上加上
(),以防止因为调用该带参宏时传参为表达式,进而由于运算符优先级的问题导致实际输出结果异常问题。 - C语言中
#以及##是两个特殊的预处理运算符,它们通常出现在宏定义过程中,在宏展开时发挥作用。这两个符号可以增强宏定义的功能以及灵活性。 -
#运算符:字符串化,也称为字符串化运算符(Stringification Operator),主要作用为将宏参数转换为字符串字面量,在宏定义中使用#时,它会将紧随其后的宏参数转换为一个带双引号的字符串。 -
##运算符:标记连接,也称为标记连接运算符(Token Pasting Operator),它的作用为将两个标记合成一个新的标记。这个特性在创建新的标识符时特别有用,特别是当我们需要基于某些参数动态生成变量名或者函数名时。(简记:拼接)#define CORE_ID 0x005U #define OS_HWCORE_ID 0x508U #define GET_OS_CORE_ID(CORE) OS_HW##CORE /* * GET_OS_CORE_ID(CORE_ID)此时就等同于OS_HWCORE_ID */ #define CORE_INDEX 5 #define OS_HW_CORE_5 10 #define CAT_INDEX(INDEX) OS_HW_CORE_##INDEX #define GET_INDEX_HW_ID(INDEX) CAT_INDEX(INDEX) /* * GET_INDEX_HW_ID(CORE_INDEX)的效果就等同于OS_HW_CORE_5,即对应的值为10 */