3.2 宏与函数的命名约定:
我们使用的宏定义函数,与普通函数的使用语法很相似,导致语言本身无法帮我们区分二者。所以我们通常对二者的命名进行约定:
①. 宏的名称全部大写。
②. 函数名不要全部大写。
如此就可以帮助我们区分,提升代码的可读性
4. 预处理操作符:
int main() { char* p = "Hellow ""world\n"; //*p指向两个常量字符串 printf("Hellow world\n"); printf("%s", p); return 0; }
当我们将其编译运行发现,打印结果均为“ Hellow world”:
于是可以得知,字符串具有自动连接的特点。那么我们是不是就可以写出下面这样的代码呢?
#define PRINT(FORMAT,VALUE) printf("The value of VALUE is "FORMAT"\n",VALUE); //可以使用宏来定义函数 //字符串"The value of VALUE is "与"\n"将会自动连接 //构造函数等价于printf("the value of VALUE is %d\n",VALUE); #include<stdio.h> int main() { int a = 10; PRINT("%d", a + 3); return 0; }
在这段代码中,我们使用了宏来构造一个新的函数,在这个我们自己构造出来的宏函数中,其中的两个短字符串将会自动连接成为一整个长字符串,并根据我们输入的参数进行打印。于是在这个过程中,就衍生出了两个实用的预处理操作符:# 与 ##。
4.1 预处理操作符 " # ":
预处理操作符" # "的作用:将宏参数转变成其对应的字符串。
这是什么意思呢?例如下面这段代码中所使用的 #N :
#define _CRT_SECURE_NO_WARNINGS 1 #define PRINT(N) printf("The value of "#N" is %d\n",N); //N将被视为字符串"N",且字符串 N 在打印时打印的是字符串 N 的内容 #include<stdio.h> int main() { int a = 10; PRINT(a + 3); return 0; }
在这段代码中,#N 将会被处理为字符串 N ,即" a + 3 ",于是整个宏定义函数就相当于:
printf("The value of ""a + 3"" is %d\n",VALUE);
即相当于字符串"The value of “、字符串"a + 3"与字符串” is %d\n"之间进行了自动连接,成为了一整个长字符串。
4.2 预处理操作符 " ## ":
预处理操作符" ## "的作用:将位于其两边的符号合成为一个符号。并且,它允许宏定义从分离的文本片段中创建标识符。
#define CAT(CLASS,NAME) CLASS##NAME //宏定义函数的作用为将符号 CLASS 与符号 NAME 合并为符号 CCLASSNAME #include<stdio.h> int main() { int class3xiaohong = 888; int back = CAT(class3, xiaohong); //使用宏定义函数 CAT ,将符号 class3 与符号 xiaohong 合并为 class3xiaohong //而符号 class3xiaohong 表示的是值为 888 的 int 类型变量,故用 int 类型变量 back 接收并打印或执行其他操作 printf("%d\n", back); return 0; }
在这段代码中,通过宏定义的预处理操作符" ## “将符号” class3 “与符号” xiaohong “进行了合并,合并成了符号” class3xiaohong “,接着我们看到,在这之前我们就已经定义并初始化了 int 类型变量 class3xiaohong,于是我们就可以使用 int 类型的变量对宏定义函数所合成的符号” class3xiaohong "所表示的值进行接收了。
5. 条件编译:
5.1 简述条件编译指令:
通过使用条件编译指令,我们在编译一段代码时如果要将一条(或一组)语句编译或舍弃是很方便的。例如一些调试性的代码就可以通过使用条件编译指令来实现选择性的进行编译。
#include<stdio.h> int main() { int arr[10] = { 0 }; int i = 0; for (i = 0; i < 10; i++) { arr[i] = i + 1; printf("%02d ", arr[i]); #if 0 printf("\n"); #endif } return 0; }
在这段代码中,包含在条件编译指令 #if 与 #endif 之间的换行打印是否执行,就取决于条件编译指令的参数,此时参数为 0 ,即为假,则不进行换行打印:
那么我们再将参数改为1,即真:
#include<stdio.h> int main() { int arr[10] = { 0 }; int i = 0; for (i = 0; i < 10; i++) { arr[i] = i + 1; printf("%02d ", arr[i]); #if 1 printf("\n"); #endif } return 0; }
这时条件编译指令参数为真,于是执行其中的代码进行换行打印
5.2 常见条件编译指令:
①. 单分支条件编译指令:
#if 常量表达式 //执行操作 #endif //或:常量表达式由预编译器求值: #define __DEBUG__ 1 #if __DEBUG__ //执行操作 #endif
②. 多分枝条件编译指令:
#if 常量表达式 //执行操作 #elif 常量表达式 //执行操作 #elif 常量表达式 //执行操作 ... #endif
③. 判断是否被定义:
#if defined(symbol) //如果 symbol 被定义过,则执行操作 #endif //或: #if !defined(symbol) //如果 symbol 没有被定义过,则执行操作 #endif
④.嵌套指令:
#if defined(MAX) #if 1 printf("%d\n", a > b ? a : b); #endif #elif defined(MIN) #if 0 printf("%d\n", a < b ? a : b); #endif #endif
通过灵活的嵌套使用条件编译指令,就能实现某条或某组程序代码的选择性编译。
7.总结:
今天我们了解了计算机的程序环境和预处理过程的相关知识,学习了掌握计算机预处理操作以及对程序编译的环境、编译链接过程以及很重要的预处理指令 #define 进行了研究,并且对条件编译相关指令和宏与函数有了一定的了解和区分,希望我的文章和讲解能对大家的学习提供一些帮助。
当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~