C&C++   发布时间:2022-04-13  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了预处理大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

宏定义

在前面的学习中经常遇到用#define命令定义符号常量的情况,其实使用#define命令就是要定义一个可替换的宏。

宏定义是预处理命令的一种,它提供了一种可以替换源代码中字符串的机制。

根据宏定义中是否有参数,可以将宏定义分为不带参数的宏定义和带参数的宏定义两种,下面分别进行介绍。

使用#define进行宏定义的好处是需要改变一个常量时只需改变#define命令行,整个程序的常量都会改变,大大提高了程序的灵活性。

宏名要简单且意义明确,一般习惯用大写字母表示以便与变量名相区别。注意 : 宏定义不是C语句,不需要在行末加分号。

不带参

#define 宏命 字符串
  • #:表示这是一条预处理命令
  • 宏命是一个标识符,必须符合 C 语言标识符的规范
  • 字符串可以是常数、表达式、格式字符串等
#define PI 3.14159

该语句的作用是在该程序中用PI替代3.14159,在编译预处理时,每当在源程序中遇到PI就自动用3.14159代替。

带参宏定义

带参宏定义不是简单的字符串替换,还要进行参数替换,其一般形式如下:

#define 宏名(参数列表) 宏体
  • 对两个参数实现混合运算 test1.c
#define MIX(x, y) ((X)*(y)+(y))
#include "stdio.h"
int main() {
    int a = 5, b = 9;
    printf("the mix num is:%d", MIX(a, b));
}

对上述代码执行 预处理命令

gcc -E test1.c

输出为(省略其他部分):

int main() {
    int a = 5, b = 9;
    printf("the mix num is:%d", ((a)*(b)+(b)));
}

可见在预处理阶段,对源码中的宏名实现了参数的代入和宏体的替换。

用宏替换代替实在的函数的一个好处是宏替换增加了代码的速度,因为不存在函数调用。但增加速度也有代价:由于重复编码而增加了程序长度。

  • 1、带参数宏定义时,参数要加括号,因为参数可能是一个表达式。如果不加括号,结果可能正确,也可能错误。或者我们在红定义的时候不带括号,但是在使用宏的地方带上括号。
#include "stdio.h"

#define MIX(x, y) ((X)*(y)+y)
#define MIX_1(x, y) (x*y+y)

int main() {
    int a = 5, b = 9;
    // 这行输出是没问题的
    printf("the mix num is : %d", MIX(a, b));
    // 这行是有问题的
    printf("the mix num is : %d", MIX_1(2 + 4, 1 + 7));
    // 这行是没问题的
    printf("the mix num is : %d", MIX_1((2 + 4), (1 + 7)));
}

同样执行预处理命令后的输出为:


int main() {
    int a = 5, b = 9;

    printf("the mix num is : %d", ((a)*(b)+b));

    printf("the mix num is : %d", (2 + 4*1 + 7 +1 + 7));

    printf("the mix num is : %d", ((2 + 4)*(1 + 7)+(1 + 7)));
}

对于宏 #define MIX_1(x, y) (x*y+y)来说,在使用的时候,给参数加上括号,也是可以是计算满足预期,但这不是好的方式。所以建议在定义宏体的时候,就给参数加上括号:#define MIX(x, y) ((X)*(y)+y)

  • 2、宏扩展必须使用括号来保护表达式中低优先级的操作符,以确保调用时达到想要的效果。
  • 3、对带参数的宏的展开,只是将语句中的宏名后面括号内的实参字符串代替#define命令行中的形参。
  • 4、在宏定义时,宏名与带参数的括号之间不可以加空格,否则会将空格以后的字符都作为替代字符串的一部分。
  • 5、在带参宏定义中,形式参数不分配内存单元,因此不必作类型定义。

include 指令

在一个源文件中使用#include指令可以将另一个源文件的全部内容包含进来,也就是将另外的文件包含到本文件之中。#include使编译程序将另一源文件嵌入带有#include的源文件,被读入的源文件必须用双引号或尖括号括起来。例如:

#include "stdio.h"
#include <stdio.h>

这两行代码均使用C编译程序读入并编译,用于处理磁盘文件库的子程序。

上面给出了双引号尖括号的形式,这两者之间的区别是

  • 用尖括号时,系统到存放C库函数头文件所在的目录中寻找要包含的文件,这为标准方式;

  • 用双引号时,系统先在用户当前目录中寻找要包含的文件,若找不到,再到存放C库函数头文件所在的目录中寻找要包含的文件。

通常情况下,如果为调用库函数用#include命令来包含相关的头文件,则用尖括号可以节省查找时间,如果要包含用户自己编写的文件,一般使用 双引号,用户自己编写的文件通常在当前目录中。如果不在,则双引号要给出文件的路径。

经常用在文件头部的被包含的文件称为“标题文件”或“头部文件”,一般以.h为后缀,如本实例中的f1.h。

一般情况下将如下内容放到.h文件中:

  • 宏定义。
  • 结构、联合和枚举声明。
  • typedef声明。
  • 外部函数声明。
  • 全局变量声明。

关于“文件包含”有以下几点需要注意

  • 一个**#include**命令只能指定一个被包含的文件。
  • 文件包含是可以嵌套的,即在一个被包含文件中还可以包含另一个被包含文件。
  • 若file1.c中包含文件file2.h,那么在预编译后就成为一个文件而不是两个文件,这时如果file2.h中有全局静态变量,则该全局变量在file1.c文件中也有效,这时不需要再用extern声明。

条件编译

预处理器提供了条件编译功能,一般情况下,源程序中所有的行都参加编译,但是有时希望只对其中一部分内容在满足一定条件时才进行编译,这时就需要使用到一些条件编译命令。使用条件编译可方便地处理程序的调试版本和正式版本,同时还会增强程序的可移植性。

if

#if的基本含义是:如果#if命令后的参数表达式为真,则编译#if#endif之间的程序段,否则跳过这段程序。#endif命令用来表示#if段的结束。

#if命令的一般形式如下:

#if 常数表达式
	语句段
#else    
#if 常数表达式
	语句段    
#endif
#endif

如果常数表达式为真,则该段程序被编译,否则跳过不编译。

大佬总结

以上是大佬教程为你收集整理的预处理全部内容,希望文章能够帮你解决预处理所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签:预处理