06- c语言预处理 (C语言)

news2024/12/24 10:53:49

一 预处理概述

1、前面各章中,已经多次使用过 #include 命令。使用库函数之前,应该用#include引入对应的头文件。这种以 #号开头的命令 称为预处理命令
2、C语言提供了多种预处理功能,如 宏定义文件包含条件编译 等。合理地使用预处理功能编写的程序便于阅读、修改、移植和调试,也有利于 模块化程序设计

在C语言中,宏(Macro)是一种预处理器指令,它用于定义和展开代码片段。宏可以在程序代码中以宏名称的形式出现,并在编译之前由预处理器进行替换。宏可以用来简化代码提高可读性实现代码复用等。

宏的定义使用 #define 关键字,后面跟着宏的名称、参数列表(可选)和宏的替换文本。宏的替换文本可以包含任何有效的C代码,它可以是 表达式语句函数调用等。

宏的展开是在编译之前由预处理器完成的,它将代码中所有使用该宏的地方替换为宏的替换文本。展开是简单的文本替换,不进行语法分析或类型检查。

宏可以接受参数,参数可以在宏的替换文本中使用,并在宏的调用处进行实际的替换。参数可以是任何有效的C表达式,包括常量、变量、函数调用等。

宏的使用可以提高代码的灵活性和效率,但也需要谨慎使用。宏展开可能导致意想不到的结果,宏参数的使用可能导致副作用,宏定义的作用域和生命周期可能导致代码行为不符合预期。因此,在使用宏时需要注意遵循一些编码规范和最佳实践,以确保代码的正确性和可维护性。

二 宏定义

1、在C语言源程序中允许用一个标识符表示一个字符串,称为“宏”。被定义为“宏”的标识符,称为“宏名”。
2、在编译预处理时对程序中所有出现的“宏名”,都用宏定义中的字符串去进行 文本替换,这称
为“宏代换”或“宏展开”。

2.1 无参宏定义

1、无参宏的宏名后不带参数,一般形式为:

#define 标识符 字符串

注意1:“字符串”可以是常量、表达式

2、举例

#define PI 3.14
#define EXP x*10*1.5

编译器在预处理时,会将源程序中所有的“PI”替换成“3.14”, 将所有的EXP, 替换成表达式“x*10 *1.5,下面我们来验证一下:

#include <stdio.h>
#define PI 3.14
#define EXP x*10*1.5
int main()
{
    float f;
    f = 10*PI;
    printf("view the data f: %f\n", f);
    float f2;
    // f2 = 10*EXP;
    return 0;
}

先将 gcc 所在的文件夹添加到 环境变量 中。

我们可以在CLion的“Terminal”下输入编译命令:gcc -E main.c -o main.i, 通过预处理将main.
c 编译成 main.i 文件,下面我们可以打开main.i文件,看看里边的内容。

3、我们发现在刚才的代码中,宏定义中出现了x,但是我们在使用时却没有定义x变量,预处理还是能够顺利通过,这是为什么呢?
宏定义是简单的文本替换,不会做语法检查 !!! 

2.2 有参宏定义

1、C语言 允许宏带有参数。在宏定义中的参数称为 形式参数,在宏调用中的参数称为实际参数。
2、对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。带参宏定义的一般形式为:

#define 宏名(形参表) 字符串

3、使用方法

#define F(x) x*x*x
int main()
{
    int r = F(3);
    return 0;
}

2.3 宏定义注意事项

1、宏定义的 “字符串” 如果是表达式,表达式中的变量需要用 () 包含起来,因为在预处理阶段展开宏时,可能会用表达式来替换宏定义中的变量。

#define F(x) (x)*(x)*(x)
int main()
{
    F(1+2);
    return 0;
}

上面的例子中展开后,(1+2)*(1+2)*(1+2),如果不加()呢?展开的表达式就变成这样了
1+2*1+2*1+2*1+2,这显然不是我们想要的结果。
2、经典笔试题:使用宏定义返回两个整数中的最大值。

#define Max(a, b) (a)>(b)?(a):(b)

三 文件包含

1、在前面的学习中我们已经使用了C语言得文件包含命令,例如:#include <stdio.h>,文件包含语法格式如下:

#include <文件名>
#include "文件名"

注意:

  • 使用 尖括号 表示 在开发环境的头文件目录 下查找,而不在源文件目录去查找。
  • 使用双引号则表示首先在当前的源文件目录中查找,如果没有找到才到包含目录中去查找。
  • “文件名” 可以是相对路径, 也可以是绝对路径,建议不要使用绝对路径。

四 条件编译

4.1、常用条件编译指令

4.2、ifdef 

#ifdef 标识符
    程序段 1
#else
    程序段 2
#endif

它的功能是,如果标识符已被 #define 命令定义过则对程序段 1 进行编译;否则对程序段 2 进行编译。如果没有程序段 2(它为空),本格式中的#else 可以没有,即可以写为:

#ifdef 标识符
    程序段
#endif

4.3、#if

经常使用 #if 0 对代码进行注释

#if 0
    代码块
#endif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/663790.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

web漏洞-反序列化之PHPJAVA全解(上)(37)

这个很重要 为什么会产生这个东西&#xff1a;序列化之后便于我们对象的传输和保存&#xff0c;这个作用就是为了数据的传递和格式的转换&#xff0c;我们称之为序列化。 在这给过程中&#xff0c;会涉及到一种叫做有类和无类的情况&#xff0c;开发里面经常看到的一个东西&a…

『免费开源』基于单片机的自动浇花系统DIY总结

功能梳理 PCB线路板采用核心板底板实现 核心板&#xff1a;排针引脚间距为2.54mm&#xff0c;2排&#xff0c;双排间距为2.54mm的倍数&#xff08;方便与面包板联用&#xff09;&#xff0c;未使用引脚全部引出&#xff0c;核心板上的主芯片为STM32F103RET6。 目的&#xff1a…

ProtoBuf 第一章、初识

一、初识 ProtoBuf 1.1序列化的概念 序列化和反序列化 序列化&#xff1a;把对象转换为字节序列的过程 称为对象的序列化。反序列化&#xff1a;把字节序列恢复为对象的过程 称为对象的反序列化。 什么情况下需要序列化 存储数据&#xff1a;当你想把的内存中的对象状态保存…

Opencv-C++笔记 (12) : opencv-仿射变化

文章目录 一、概述二、GetRotationMatrix2D三、warpAffine() 一、概述 介绍完图像的缩放和翻转后&#xff0c;接下来将要介绍图像的旋转&#xff0c;但是在OpenCV 4中并没有专门用于图像旋转的函数&#xff0c;而是通过图像的仿射变换实现图像的旋转。实现图像的旋转首先需要确…

MT6704 应用

MT6704 是用于反激式变换器的高性能 40V 同步整流器。它兼容各种反激转换器类型。支持 DCM、CCM 和准谐振模式。MT6704 集 成 了 一 个 40V 功 率MOSFET&#xff0c;MT6704可以取代肖特基二极管&#xff0c;提高效率。V SW <V TH-ON 时&#xff0c;内部 MOSFET 导通。 V SW …

【JavaEE】网络层和数据链路层重点协议:IP和以太网

目录 1、IP协议 1.1、IP协议报头 1.2、解决IPv4地址不够用的问题 2、IP地址管理 2.1、IP地址的组成 2.1.1、子网掩码 2.1.2、IP地址的分类 3、路由选择 4、数据链路层协议&#xff1a;以太网协议 1、IP协议 IP协议属于TCP/IP模型的网络层&#xff0c;在网络层协议存在…

volatile,wait和notify,懒汉模式和饿汉模式,阻塞式队列,定时器

目录 可见性 volatile volatile保证内存可见性 volatile不保证原子性 synchronized也可以保证内存可见性 wait和notify wait () notify() notifyAll() wait和sleep对比 顺序执行ABC三个线程 单例模式 饿汉模式 懒汉模式 懒汉模式和饿汉模式在多线程环境下调用getInstance,是否…

将条码图片批量嵌入到Excel单元格中

项目源码&#xff08;如果有帮助希望可以点一个star&#xff09; 业务场景&#xff1a; 需要将条码图片存到excel之中方便归档。 效果展示&#xff1a; 直接运行org.example.Main.main()就会将file目录中的图片插入到excel中&#xff0c;并且在项目根目录会生成一个.xlsx文件…

CTFshow-pwn入门-前置基础pwn20-pwn22

pwn20-pwn22是关于.got节跟.got.plt节的。这3道题的问题描述全是一样的&#xff0c;全都是问.got跟.got.plt是否可写以及他们的地址是什么&#xff0c;然后根据这些信息来拼成flag。那么关于.got和.got.plt的内容非常复杂&#xff0c;这里呢我也不解释了&#xff0c;推荐一个牛…

【kubernetes】负载均衡器安装部署-Haproxy与keepalived

前言:二进制部署kubernetes集群在企业应用中扮演着非常重要的角色。无论是集群升级,还是证书设置有效期都非常方便,也是从事云原生相关工作从入门到精通不得不迈过的坎。通过本系列文章,你将从虚拟机准备开始,到使用二进制方式从零到一搭建起安全稳定的高可用kubernetes集…

不要再用 count(*) 查询记录数了

来源 | 苏三说技术 &#xff08;ID&#xff1a;susanSayJava&#xff09; 已获得原公众号的授权转载 前言 最近我在公司优化过几个慢查询接口的性能&#xff0c;总结了一些心得体会拿出来跟大家一起分享一下&#xff0c;希望对你会有所帮助。 我们使用的数据库是Mysql8&…

【6.19】用户自己写String类会发生什么(双亲委派机制)

用户自己写一个String类会发生什么&#xff1f; 了解“类加载器” Java是运行在Java的虚拟机&#xff08;JVM&#xff09;中的。我们在IDE里编写的Java源代码先编译成.class的字节码文件&#xff0c;再由ClassLoader将class文件加载到JVM中执行。 JVM中有三层ClassLoader&am…

apple pc install windows 10

苹果笔记本安装window10&#xff0c;做个U盘启动&#xff0c;开机狂摁option&#xff0c;选择U盘&#xff0c;当然你最好去windows官方下个镜像&#xff0c;避免我前面出现提出镜像不行。另外苹果后来机器好像不能安windows了。呼呼…

GPT-3解数学题准确率升至92.5%!无需微调即可打造理科语言模型

原文&#xff1a;百度安全验证 【新智元导读】ChatGPT的文科脑有救了&#xff01; 大型语言模型最为人诟病的缺点&#xff0c;除了一本正经地胡言乱语以外&#xff0c;估计就是「不会算数」了。 比如一个需要多步推理的复杂数学问题&#xff0c;语言模型通常都无法给出正确答…

很有必要更新:LightningChart.NET 10.5.1 Crack

LightningChart.NET v10.5.1版本--这个版本比SciChart 更好&#xff0c;更快&#xff0c;更强 为所有3D、Polar和Smith系列添加DataCursor功能。 2023年6月19日-10:53新版 特点 为所有3D、Polar和Smith系列启用了DataCursor功能。DataCursor允许用户浏览一个系列&#xff0…

【一起啃书】《机器学习》第十章 降维与度量学习

文章目录 第十章 降维与度量学习10.1 k k k近邻学习10.2 低维嵌入10.3 主成分分析10.3.1 定义与步骤10.3.2 最近重构性与最大可分性 10.4 核化线性降维10.5 流形学习10.6 度量学习 第十章 降维与度量学习 10.1 k k k近邻学习 k k k近邻学习是一种常用的监督学习方法&#xf…

数字图像处理实验报告(二)

报告目录 实验四、图像复原 实验五、图像压缩及编码 实验四、图像复原 一、实验目的 了解图像复原的意义和手段&#xff1b;熟悉图像退化成因及处理方法&#xff1b;通过实验了解不同图像退化模型的特点&#xff1b;通过本实验掌握利用MATLAB建立图像退化模型并进行复原的方…

linux CentOS7 keepalived+LVS(DR)搭建部署

目录 一、服务器准备 二、操作步骤 1.部署web服务器 2.部署LVS主备调度器 测试 部署NFS共享服务器 一、服务器准备 .准备6台虚拟机&#xff0c;2台做LVS主备调度器&#xff0c;2台做web服务器&#xff0c;1台做存储&#xff0c;1台客户机验证 1.LVS主调度器 &#xff08…

20个你应该掌握的强大而有用的正则表达式

关注“大前端私房菜”微信公众号&#xff0c;回复暗号【面试宝典】即可免费领取107页前端面试题。 正则表达式是一种很强大的字符串模式匹配工具。掌握常见的正则表达式可以大大提高我们在字符串操作和文本处理上的效率。 1.货币格式化 我经常需要在工作中使用到格式化的货币&…