首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >编译预处理

编译预处理

作者头像
用户7272142
发布2023-10-11 21:12:09
发布2023-10-11 21:12:09
6670
举报
文章被收录于专栏:Republic博客Republic博客

编译预处理是对C语言源程序编译前进行的预加工,这些操作是通过命令来实现的,即预编译命令,主要有三种,即宏定义、文件包含和条件编译。这些规定是由编译系统规定的,由于不是C语言本身的组成部分,因此不能直接编译,而要经过编译器预处理再与源程序进行编译 书写规则:#+关键字(一行书写一个)

宏定义

用一个指定的标识符(名字)来代表一个字符串。

不带参数的宏定义

格式:#define 标识符 字符串 用标识符来代替字符串,在程序中出现宏名的位置,经过编译器的处理,被替换成对应的宏字符串,称为宏展开。标识符又称为宏名,通常用大写字母来表示,字符串称为宏体,一般是常数、关键词、语句、表达式等,也可以是空白,末尾不用分号。宏名的有效范围是从定义命令开始到程序结束,通常写在程序的开头,比如#define PI 3.1415926 根据源程序中出现PI用3.1415926来替换

代码语言:javascript
复制
#include <stdio.h>
#define PI 3.1415926
int main()
{
float r = 6;
float l,s,v;
l = 2.0 * PI * r;
s = PI*r*r;
v = 4.0/3*PI*r*r*r;
printf("r = %.2f\nl = %.2f\ns = %.2f\nv = %.2f\n",r,l,s,v);
}

宏展开只是简单的用定义的宏体替换宏名,由于是替换,所以宏定义中有无圆括号效果是不同的

比如

代码语言:javascript
复制
#define W 80
#define L W+40 
#define S L*W
int main()
{

printf("L = %d\nW = %d\nS = %d\n",L,W,S);
}

如果没有括号那么S将会被替换成80+40*80 很明显是不对的,所以需要用圆括号 另外在printf内,双引号中的LWS没有被替换,仅替换不在双引号以内的,制作字符串替换,并不会分配和占用内存。

带参数的宏定义

\#define 标识符(形参表) 字符串 其中字符串包含形参参数,一般为表达式,也可以包括宏名和函数。使用带参宏时候,一定要注意要用实参替换形参。 宏展开通过宏体替换宏名(直接置换宏定义命令中相应的形参字符串,非形参字符保持不变)

代码语言:javascript
复制
#define V(l,w,h) l*w*h
...
VOLUME = v(4,2,8);

经过宏展开之后,赋值语句为4*2*8 按照宏定义的形参表的顺序从左向右进行置换,对于非形参字符*保留 带参数的宏定义中也可以引用已定义的宏定义

代码语言:javascript
复制
#define PI 3.1415926
#define S(r) PI*r*r
#define V(r) 4.0/3*S(r)*r

预处理是对每个宏名进行展开替换,直到程序中不再有宏名为止,我们来试着宏展开一下 假设V(3) = 4.0/3*S(3)*3 V(3) = 4.0/3*PI*3*3*3 V(3) = 4.0/3*3.1415926*3*3*3 宏替换中的实参广义上是一个字符串,一般为常量、变量或表达式。所以V的实参可以为(3*a)等 当然也可以用函数定义,带参数的宏和函数虽有很多相似之处,但二者在本质是不一样的。

  1. 函数调用需要分配内存和存储单元。而宏替换是在编译时进行的,仅仅进行替换 例如:#define sqr(x) (x)*(x) 在调用时有y=sqr(a+b);宏展开时候,直接用a+b替换x的值,函数的形参和实参要求类型兼容,而宏定义只是进行符号的替换。
  2. 函数调用占用程序运行时间,宏展开占用编译时间
  3. 参数和宏名之间没有空格,如果有空格,宏名会被定义为一个符号常量
  4. 如果宏展开后根据优先级可能会有误解,则需要在宏定义时候加上圆括号 解除宏定义 接触宏定义 作用:限定宏定义的作用域在某一个范围内,可以用\#undef 命令来解除已有的宏定义 格式:#undef 宏名 \#define MAX 100 ... \#undef MAX 使得MAX在undef之前有效,之后便不再有效 重新宏定义 undef的另一个作用是重新进行宏定义,C语言中宏不能重复定义,即程序中不能使用同名的宏。若要重新定义,需先解除已有定义,再进行新的定义 文件包含 格式:#include<文件名> 或 \#include "文件名" <>会先在C语言库函数中查找 ""会先在本地目录查找,找不到再到库函数中去找,一次只能包含一个文件,在编译预处理时,文件包含命令行被包含进来的文件替换,成为源文件的一部分,与其他源文件一起参加编译。

条件编译 一般情况下,源程序中的所有语句都参加编译,但是我们有时会需要满足某种条件时才被编译。 条件编译命令格式 \#ifdef 标识符 程序段1 \#else 程序段2 \#endif 若标识符已被定义过,则编译程序1否则编译程序2 \#if 标识符 程序段1 \#else 程序段2 \#endif 若指定表达式的值为真,则程序段1参加编译,否则程序段2参加编译 \#ifndef 程序段1 \#else 程序段2 \#endif 若标识符未被定义,则编译程序段1,否则编译程序段2

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-09-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 宏定义
    • 不带参数的宏定义
    • 带参数的宏定义
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档