C语言:预处理详解(知识点和代码演示)

和黛玉学编程........>


预定义符号

__FILE__ //进行编译的源文件
__LINE__ //文件当前的行号
__DATE__ //文件被编译的日期
__TIME__ //文件被编译的时间
__STDC__ //如果编译器遵循ANSI C,其值为1,否则未定义

比如:d576f738cf314f76a6ee0bc6c8617d87.png

 #define定义常量

#define name stuff 

 注意:在定义标书符的时候,建议不要在最后加上;  容易导致问题

比如这种情况:

if(condition)
max = MAX;
else
max = 0;

这里的if和else就是变成两条语句了

d29800001fdc40858cacc8c8bfca6d23.png

 

#define定义宏

#define机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro)

 #define name( parament-list ) stuff

    parament-list 是⼀个由逗号隔开的符号表,它们可能出现在stuff中(参数列表的左括号必须与name紧邻,如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分)

 举个例子:#define SQUARE( x ) ((x) *(x))

 这里我们需要注意一下这里的x需要加上括号,最好是,不然结果容易出错

      所以用于对数值表达式进⾏求值的宏定义都应该用这种方式加上括号,避免在使⽤宏时由于参数中的操作符或邻近操作符之间不可预料的相互作用。

 比如:如果你不加括号就出错啦

printf ("%d\n",a + 1 * a + 1 );

14958a083d004ad98ee9709220b52c75.png

 

带有副作用的宏参数

 x+1; //不带副作用
x++; //带有副作用

也就是我们的参数可能在使用过程中改变了自身的值,所以使用的时候你需要小心哦 

 宏替换的规则

1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。
2. 替换文本随后被插人到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程

宏函数的对比

宏经常被用于执行简单运算,比如加减法,找两个数的最大

#definr MAX(a,b) ((a)>(b)?(a):(b))

这个时候就有人说了,我都会函数了,为什么不使用函数呢

 原因如

1. ⽤于调⽤函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序的规模和速度方面更胜⼀筹。
2. 更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使⽤。反之
这个宏怎可以适用于整形、长整型、浮点型等可以⽤于 > 来比较的类型。宏是类型无关的。

 所以宏的参数可以出现类型

#define MALLOC(num, type)\
(type )malloc(num sizeof(type))
...
//使⽤
MALLOC(10, int); //类型作为参数
//预处理器替换之后:
(int )malloc(10 sizeof(int));

 但是并不是宏就是最好的

1. 每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。
2. 宏是没法调试的。
3. 宏由于类型无关,也就不够严谨。
4. 宏可能会带来运算符优先级的问题,导致程容易出现错。

所以勒,就需要大家打代码的时候多多动脑子啦 

373715cef6c54fa8b6eddc9e11f8ef5d.png

 

 #和##

#

#运算符所执行的操作可以理解为”字符串化“

比如:我们想打印出: the value of a is 10

可以写

#define PRINT(n) printf("the value of "#n " is %d", n); 
printf("the value of ""a" " is %d", a); 

在打印的时候上面的#n就会被下面的a替换掉

##

## 可以把位于它两边的符号合成⼀个符号,它允许宏定义从分离的文本片段创建标识符。 ## 被称为记号粘合

比如我们要求两个数的较大值的时候

#define GENERIC_MAX(type) \
type type##_max(type x, type y)\
{ \
return (x>y?x:y); \
}
GENERIC_MAX(int) 
GENERIC_MAX(float)
int main()
{
int m = int_max(2, 3);
printf("%d\n", m);
float fm = float_max(3.5f, 4.5f);
printf("%f\n", fm);
return 0;
}

type type##_max(type x, type y)如果输入int 就可以变成int int-max(int x,int y)

但是在实际情况里面,这个使用比较少

#undef

这条指令⽤于移除一个宏定义

#undef NAME

 命令行定义

许多C的编译器提供了⼀种能力,允许在命令行中定义符号。⽤于启动编译过程。

#include <stdio.h>
int main()
{
int array [ARRAY_SIZE];
int i = 0;
for(i = 0; i< ARRAY_SIZE; i ++)
{
array[i] = i;
}
for(i = 0; i< ARRAY_SIZE; i ++)
{
printf("%d " ,array[i]);
}
printf("\n" );
return 0;
}

 编译指令

gcc -D ARRAY_SIZE=10 programe.c

 条件编译

在编译⼀个程序的时候我们如果要将一条语句(一组语句)编译或者放弃是很方便的

比如代码:

#include <stdio.h>
#define __DEBUG__
int main()
{
 int i = 0;
 int arr[10] = {0};
 for(i=0; i<10; i++)
  {
   arr[i] = i;
   #ifdef __DEBUG__
   printf("%d\n", arr[i]); 
   #endif //__DEBUG__
  }
 return 0;
}

常见的:

//1.
#if 常量表达式
//...
#endif
//常量表达式由预处理器求值。
//如:
#define __DEBUG__ 1
#if __DEBUG__
//..
#endif
//2.多个分⽀的条件编译
#if 常量表达式
//...
#elif 常量表达式
//...
#else
//...
#endif
//3.判断是否被定义
#if defined(symbol)
#ifdef symbol
#if !defined(symbol)
#ifndef symbol
//4.嵌套指令
#if defined(OS_UNIX)
   #ifdef OPTION1
         unix_version_option1();
   #endif
   #ifdef OPTION2
        unix_version_option2();
   #endif
#elif defined(OS_MSDOS)
   #ifdef OPTION2
        msdos_version_option2();
   #endif
#endif

头文件的包含

本地文件

#include "filename"

 先在源文件所在目录下查找,如果该头文件未找到,编译器就像查找库函数头头件⼀样在
标准位置查找头文件。如果找不到就提示编译错误

 Linux环境和vs环境的标准头文件的路径是不一样的

库文件

#include <filename.h>

 查找头文件直接去标准路径下去查找,如果找不到就提示编译错误

 嵌套文件的包含

我们已经知道, #include 指令可以使另外⼀个件文被编译。
这种替换的⽅式很简单:预处理器先删除这条指令,并用包含文件的内容替换。
⼀个头文件被包含10次,那就实际被编译10次,如果重复包含,对编译的压力就比较大。

 那就可以:

#ifndef __TEST_H__
#define __TEST_H__
//头⽂件的内容
#endif //__TEST_H__

或者

#pragma once

 感谢阅读到这里,里面许多东西还是需要自己多多练习才能熟能生巧哦!

大家加油!

对你有帮助不如点个赞,关个注wow~~~~~~~~~~~

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Visual Studio2022使用(后续使用到再更新)

安装 从官网安装&#xff0c;下载即可。注意&#xff1a;选择社区版。&#xff08;免费够用&#xff09; 安装好后打开安装包&#xff0c;会继续下载东西&#xff0c;挂几个小时差不多就下好了。 使用 1、打开VS&#xff0c;点击“创建新项目”&#xff0c;选择“空项目”。…

【图论】 【割点】 【双连通分类】LCP 54. 夺回据点

本文涉及知识点 图论 割点 双连通分类 割点原理及封装好的割点类 LeetCode LCP 54. 夺回据点 魔物了占领若干据点&#xff0c;这些据点被若干条道路相连接&#xff0c;roads[i] [x, y] 表示编号 x、y 的两个据点通过一条道路连接。 现在勇者要将按照以下原则将这些据点逐一…

5分钟搭好一个易支付,个人最简单的对接支付宝方式

最近在疯狂折腾网站相关的知识,搭建了另一个平台后,需要涉及支付相关的内容。即 用户在某个平台请求支付时候,对接第三方支付支付宝,收款信息是我的,然后支付成功后给与回调。网上很多易支付网站,但是这玩意儿,既然咱碰到了,咱就自己弄。那么说搞咱就搞。 假设你已经搭…

Kafka MQ 生产者和消费者

Kafka MQ 生产者和消费者 Kafka 的客户端就是 Kafka 系统的用户&#xff0c;它们被分为两种基本类型:生产者和消费者。除 此之外&#xff0c;还有其他高级客户端 API——用于数据集成的 Kafka Connect API 和用于流式处理 的 Kafka Streams。这些高级客户端 API 使用生产者和消…

BUUCTF---easyre1

1.记录一下第一次做逆向题目 2.题目描述&#xff0c;下载附件 3.解压之后是一个可执行文件&#xff0c;先用PE查看是否有壳 4.没有壳&#xff0c;接下来用ida打开&#xff0c;直接拖进ida即可&#xff0c;接下来使用快捷键fnshiftf12查看字符&#xff0c;若是没有出现搜索框&a…

收割机案例-简单的动态规划

#include<iostream> using namespace std; // 创建土地 short land[32][32]; short n,m;// 实际使用的土地大小 short landA[32][32];//用A收割机收割数量记录 short landB[32][32];// 用B收割机收割数量记录 int main(){cin>>n>>m;// 存储农作物产量for(sho…

GNN-Transformer新突破!全局与局部的完美融合

图神经网络&#xff08;GNN&#xff09;和Transformer的结合是近年来的研究热点。这类结合不仅能够让两者发挥各自的优势&#xff0c;还能推动模型的创新&#xff0c;提高处理图数据的效率和性能。 具体点讲&#xff0c;通过利用Transformer&#xff0c;我们可以扩展GNN的感受…

Spring boot 操作 Redis

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 往期热门专栏回顾 专栏…

nginx-排查一次大文件无法正常下载问题

目录 问题现象&报错信息 问题现象以及分析 nginx报错信息 问题解决 方法1&#xff1a;配置proxy_max_temp_file_size 方法2&#xff1a;关闭proxy_buffering 参考文档 问题现象&报错信息 问题现象以及分析 文件正常从后端服务器直接下载时&#xff0c;一切正常…

【git bug】warning: auto-detection of host provider took too long (>2000ms)

【git bug】warning: auto-detection of host provider took too long (>2000ms) 报错问题&#xff1a; warning: auto-detection of host provider took too long (>2000ms) 报错截图&#xff1a; 报错描述&#xff1a; 在windows操作系统&#xff0c;未连接互连网电…

java之mybatis

准备工作 上面4步骤 XML映射文件 动态SQL

掘根宝典之c++有符号(signed)和无符号类型(unsigned)

在c中&#xff0c;有符号和无符号是针对整型而言的 在C中&#xff0c;除了布尔类型和拓展的字符类型之外&#xff0c;其他整型可以划分为有符号类型&#xff08;signed&#xff09;和无符号类型&#xff08;unsigned&#xff09;&#xff0c;用于表示整数。 有符号类型可以表…

参与Penpad launch任务,实现Penpad与Scroll的双空投

在比特币 ETF 、BTC 减半等利好消息的持续推动下&#xff0c;加密市场逐渐进入到新一轮牛市周期中。除了以太坊 Layer1 生态 TVL 不断飙升外&#xff0c;Layer2 赛道 TVL 也在不断飙升并且屡创新高。 而在牛市背景下&#xff0c;Layer2 空投所带来的财富效应预期正在被进一步拉…

AD20新建工程步骤

1 新建工程 2 创建 3 新建原理图 4 新建PCB图 5 对原理图贺PCB都进行保存 6 新建原理图库贺PCB库&#xff0c;以及保存 最后在保存位置上都可以看到 打开的时候直接打开工程&#xff0c;它自己就会把这些链接在一起

笔记本电脑使用时需要一直插电吗?笔记本正确的充电方式

随着科技的不断发展&#xff0c;笔记本电脑已经成为人们日常生活和工作中不可或缺的电子设备。而在使用笔记本电脑时&#xff0c;很多人会有一个疑问&#xff0c;那就是笔记本电脑使用时需要一直插电吗&#xff1f;本文将就此问题展开讨论。 不一定需要一直插电&#xff0c;如果…

Linux网络基础3之IP协议

(&#xff61;&#xff65;∀&#xff65;)&#xff89;&#xff9e;嗨&#xff01;你好这里是ky233的主页&#xff1a;这里是ky233的主页&#xff0c;欢迎光临~https://blog.csdn.net/ky233?typeblog 点个关注不迷路⌯▾⌯ 目前已经学完了应用层以及传输层&#xff0c;我们应…

系统学习c++类和对象——深度理解默认成员函数

前言&#xff1a;类和对象是面向对象语言的重要概念。 c身为一门既面向过程&#xff0c;又面向对象的语言。 想要学习c&#xff0c; 首先同样要先了解类和对象。 本节就类和对象的几种构造函数相关内容进行深入的讲解。 目录 类和对象的基本概念 封装 类域和类体 访问限定符…

单片机灭火避障小车设计

目录 目录 II 摘要 III 1 智能小车概述 5 1.1 国内外研究动态 5 1.2 课题的目的和意义 5 2 系统设计概述 6 2.1 系统设计要求 6 2 总体方案设计 7 2.1 硬件设计 7 2.1.1 车体设计 7 2.1.2 主控制器模块 8 2.1.3 电源模块 8 2.1.4 电机驱动模块 9 2.2 火源检测模块 10 2.3 避障…

vue实现图片框选标注

前言 前端有一个需求&#xff0c;对上传的图片进行检测识别&#xff0c;通过返回的接口坐标数据&#xff0c;对图片的某些区域进行框选并标注。如图&#xff1a; 开始 1、上传功能使用elementui的upload插件&#xff1b; 2、在图片上进行标注功能是元素定位在图片上层&#x…

小程序对于人力资源行业的创新与变革

随着移动互联网的快速发展&#xff0c;小程序成为了各行各业推广和服务的新利器。对于人力资源行业来说&#xff0c;开发一款定制化的小程序不仅可以提升服务效率&#xff0c;还可以增强品牌形象和用户粘性。那么&#xff0c;如何定制开发人力资源类的小程序呢&#xff1f;下面…
最新文章