ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

#define和#、##、@#解析:

#define和#、##、@#解析: 目录前言1.什么是预处理2.#define是什么一.关于#define:1.#define 的标识符定义2.#define 的函数定义3#define 的续行操作4#define 的常见作用a.方便维护b.方便程序员检测c.简化写法d.进行条件编译二.关于字符串常量化运算符 # 1.常见用法:2.对空格处理三.符号连接操作符符 ##四.单字符化操作符 # 注意事项前言1.什么是预处理C语言源文件要经过预处理、编译、链接才能生成可执行程序。预处理就是再编译前对源文件进行简单的加工处理。预处理主要是以 # 开头的命令例如 #includestdio.h #define 等。预处理命令要放在所有函数之外而且一般都放在源文件的前面。2.#define是什么#define 属于预处理器指令可以将一些常量或代码模块定义为宏在预处理是进行文本替换这个行为被称为宏替换或宏展开。一.关于#define:1.#define 的标识符定义定义标识符是 #define 最常见的用法也可以说是没有参数的宏定义。流程为#define ----- 标识符也叫宏名、宏 ------替换列表。示例#includestdio.h #define num 20 #define print printf int main() { print(%d, num); return 0; }运行结果如下图这里是一个简单的宏定义我们使用预处理指令 #define 定义了一个名为 print 和 num“printf” 和“num 在预处理阶段会被替换成函数 printf 和 20。2.#define 的函数定义简单来说就是 #define 的宏定义可以像函数一样接受参数。示例#includestdio.h #define add(x, y) ((x)(y)) #define max(x, y) ((x) (y) ?x:y) int main() { printf(%d\n, add(2, 3)); printf(%d\n, max(2, 3)); return 0; }运行结果如下图所示这里我们定义了两个名为 add max 的宏进行文本替换后分别求出参数之和和参数中最大值。3#define 的续行操作顾名思义就是将 #define 的替换列表放在二行及更多行上。示例#includestdio.h #define for(x) for(int i 0; i x; i)\ {\ printf(%2d,i);\ } int main() { for (5); return 0; }运行结果如下图由上我们可以知道#define 的多行定义关键是要在每一个换行的时候加上一个/。4#define 的常见作用a.方便维护示例#define size 100; int a[size];这里创建了一个数组当以后数组觉得数组太大或是太小我们可以通过改变宏定义的替换列表来一键改变数组 a 的大小。b.方便程序员检测当看别人的代码时或者回头观看以前的代码通常会忘记一个代码块代表的含义当使用如 add 等宏定义的函数时可以帮助我们快速理解。c.简化写法示例#define usi unsigned short int usi a;当我们需要经常使用 unsigned short int 时由于该类型较长经常会 觉得麻烦这时候就可以通过将其定义为 usi 并可以通过 usi 创建变量。d.进行条件编译示例#includestdio.h #define add 0 int main() { #ifdef add printf(1); #endif return 0; }运行结果如下如上图当 add 被定义时预处理指令 #ifdef 和 #endif 中的语句执行当讲 add 的宏定义注释掉时预处理指令中的语句不执行。二.关于字符串常量化运算符 # 1.常见用法:示例#includestdio.h #define print(a,b) printf(#a and %d,b) int main() { print(abc,3); return 0; }运行结果如下图所示由此我们可以知道在宏定义中当需要把一个宏的参数转换为字符串常量时则使用字符串常量化运算符#。在宏中使用的该运算符有一个特定的参数或参数列表。2.对空格处理示例#includestdio.h #define print(a,b) printf(#a and %d,b) int main() { print( a bc ,3); return 0; }运行结果如下图由此我们可以知道编译器会将子字符或者字子符串使用空格连接并丢弃字符或字符串两边的空格。三.符号连接操作符符 ##示例#includestdio.h #define num1 100 #define num(a) num##a int main() { printf(%d, num(1)); return 0; }运行结果如下图这里我们通过符号链接操作符 ## 将 num 和 1 连接成 num1 。注1.宏展开时 ## 两边的空格会自动去除。2.连接后的实际参数名必须为实际存在的参数名或是编译器已知的宏定义。3.如果##后的参数本身也是一个宏的话##会阻止这个宏的展开。四.单字符化操作符 # 用法与##类似。示例#includestdio.h #define fun(x) #x int main() { printf(%c, fun(a)); return 0; }运行结果如下所示这里通过 # 操作符将 a 转换成字符。注单字符化操作符# 最多有四个参数并只返回最后一个字符当参数超过四个时系统将报错。注意事项1.define是宏定义程序在预处理阶段将用define定义的内容进行了 替换 。因此在程序运行时常量表中并没有用define定义的常量系统不为它分配内存。2.define没有类型检查的功能因为它只进行文本替换。它只是简单地将宏调用替换为宏定义中指定的文本没有对文本进行语法分析和类型检查。这种情况下类型错误很容易发生特别是对于复杂的宏定义。3.define定义表达式时要注意“边缘效应”。示例#includestdio.h #define fun(a,b) ab int main() { printf(%d, fun(1, 2) * fun(3, 4)); return 0; }运行结果如下所示对于这个代码我们想得到的值为21 但是实际的值为11 。这是为什么我们将宏展开看看#includestdio.h int main() { printf(%d, 12*34); return 0; }这里本应该先和 1 相加的 2 却先与 3 相乘所以结果错误。我们可以通过多加括号来改变表达式运算顺序来预防“边缘效应”。4.define 宏定义后直到遇到 #undef 之前可以一直使用在 #undef 后先前的宏需要再次定义才能够使用。5.带副作用的宏参数示例#includestdio.h #define max(x,y) ((x)(y)?(x):(y)) int main() { int a 1, b 2; int c max(a, b); printf(%d, c); return 0; }这里宏展开后得到表达式 c ((a)(b)?(a):(b))这个式子的值与编译器有关就大大降低了代码的可移植性。
返回列表