当前位置: 首页 > news >正文

预处理详解(二)

目录

  • #与##运算符
    • #运算符
  • ##运算符
    • 被称为记号粘合
  • 命名约定
  • #undef
  • 条件编译
  • 常见的条件编译指令
  • 头文件的包含
    • 本地头文件包含
    • 库函数头文件包含
    • 嵌套文件包含

#与##运算符

#运算符

当我们有⼀个变量 int a = 10; 的时候,我们想打印出: the value of a is 10 就可以写:

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

当我们按照下⾯的方式调用的时候:
PRINT(a);当我们把a替换到宏的体内时,就出现了#a,⽽#a就是转换为"a"⼀个字符。
代码就会被预处理为:

printf("the value of ""a" " is %d", a);

##运算符

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

被称为记号粘合

这样的连接必须产⽣⼀个合法的标识符。否则其结果就是未定义的。
写⼀个函数求2个数的较⼤值的时候,不同的数据类型就得写不同的函数。但是宏不用。
比如:

//宏定义
#define GENERIC_MAX(type) \
type type##_max(type x, type y)\
{ \return (x>y?x:y); \
}
GENERIC_MAX(int) //替换到宏体内后int##_max ⽣成了新的符号 int_max做函数名
GENERIC_MAX(float) //替换到宏体内后float##_max ⽣成了新的符号 float_max做函数名
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;
}

在这里插入图片描述
但是这个在实际开发中用的很少,了解一下即可。

命名约定

⼀般来讲函数的宏的使宏语法很相似。所以语言本⾝没法帮我们区分⼆者。
那我们平时的⼀个习惯是:
把宏名全部大写
函数名不要全部大写

#undef

它的作用是移除一个宏定义:

#define M 100
int main()
{printf("the value = %d\n",M);
#undef Mprintf("the value = M");return 0;
}

在这里插入图片描述

条件编译

在编译⼀个程序的时候我们如果要将⼀条语句(⼀组语句)编译或者放弃是很⽅便的。因为我们有条件编译指令。
比如:
一些用来调试的代码检查这段代码是否执行,调试完后删了可惜,保留又没什么用,就可以用条件编译指令。

#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;
}

当我们定义了__DEBUG__,就会打印,没有定义就直接跳到endif。

常见的条件编译指令

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 OPTION1unix_version_option1();#endif#ifdef OPTION2unix_version_option2();#endif
#elif defined(OS_MSDOS)#ifdef OPTION2msdos_version_option2();#endif
#endif

头文件的包含

本地头文件包含

#include "test.h"

这是我们包含自己创建的头文件的方式,当我们使用这种方式包含头文件,编译器会在我们创建工程的地方寻找这个头文件,当工程文件找不到,才会去标准库函数的文件里面去找。

库函数头文件包含

#include <filename.h>

查找头文件直接去标准路径下去查找,如果找不到就提示编译错误。
这样是不是可以说,对于库⽂件也可以使⽤ “” 的形式包含?
答案是肯定的,可以,但是这样做查找的效率就低些,当然这样也不容易区分是库文件还是本地文件了。
要是用库函数的形式包含自建头文件,就会先去标准库里面查找,找不到才会在工程文件里面找,会浪费时间。

嵌套文件包含

在我们写程序时可能一个头文件要在多个.c文件里面包含,预编译时会将头文件替换成它的函数内容,这样在编译时就会出现重复编译,使得代码很繁琐。
这个时候我们就可以用条件编译来解决这个问题:

#ifndef __test_H_//是否定义了“__test_H_”
//没有定义就编译,定义过就跳转到#endif
#define __test_H_
void 函数名();
#endif

这样在编译时,第一次编译头文件,因为前面的代码是否定义了“_test_H”,没有就编译一次,当第二次时,因为前面已经定义过了,所以就不会进行二次编译,这样就避免了重复编译的可能。
预编译指令还有很多,有兴趣的可以参考《C语言深度解剖》学习
---------------------------------------------------分隔符
对预处理的介绍就结束了,感谢各位观看。
有错请在评论区指正,共勉!

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【Android Studio】2024.1.1最新版本AS调试老项目(老版AS项目文件、旧gradle)导入其他人的项目
  • bat批量修改文件名
  • C++ 萃取技术——值萃取
  • 机器学习(Machine Learning, ML)和深度学习(Deep Learning, DL)对比
  • c4d的重命名工具(支持模型和材质) 及 python窗口定义
  • 第四天旅游线路预览——从贾登峪到喀纳斯景区入口(贾登峪游客服务中心)
  • [数据集][目标检测]智慧交通铁路异物入侵检测数据集VOC+YOLO格式802张7类别
  • [网络][CISCO]Cisco-PIX配置详解
  • 创建Django 项目
  • 【python计算机视觉编程——10.OpenCV】
  • 图新地球-将地图上大量的地标点批量输出坐标到csv文件【kml转excel】
  • Linux驱动开发-字符设备驱动开发
  • 如何在本地计算机中打开远程服务器的Jupyter notebook
  • leetcode hot100刷题【持续更新】
  • 深度挖掘| 如何高效实现Cloudera 安装之基础环境搭建
  • 【干货分享】SpringCloud微服务架构分布式组件如何共享session对象
  • 【面试系列】之二:关于js原型
  • express.js的介绍及使用
  • java8 Stream Pipelines 浅析
  • Js实现点击查看全文(类似今日头条、知乎日报效果)
  • Otto开发初探——微服务依赖管理新利器
  • python_bomb----数据类型总结
  • springMvc学习笔记(2)
  • vue+element后台管理系统,从后端获取路由表,并正常渲染
  • 翻译:Hystrix - How To Use
  • 基于 Babel 的 npm 包最小化设置
  • 利用阿里云 OSS 搭建私有 Docker 仓库
  • 聊一聊前端的监控
  • 批量截取pdf文件
  • 前端_面试
  • 前端js -- this指向总结。
  • 全栈开发——Linux
  • 如何借助 NoSQL 提高 JPA 应用性能
  • 腾讯优测优分享 | 你是否体验过Android手机插入耳机后仍外放的尴尬?
  • 2017年360最后一道编程题
  • 如何在 Intellij IDEA 更高效地将应用部署到容器服务 Kubernetes ...
  • 小白应该如何快速入门阿里云服务器,新手使用ECS的方法 ...
  • ​​​​​​​STM32通过SPI硬件读写W25Q64
  • ​DB-Engines 11月数据库排名:PostgreSQL坐稳同期涨幅榜冠军宝座
  • ​html.parser --- 简单的 HTML 和 XHTML 解析器​
  • ###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯
  • #{} 和 ${}区别
  • #我与虚拟机的故事#连载20:周志明虚拟机第 3 版:到底值不值得买?
  • (1)bark-ml
  • (1)svelte 教程:hello world
  • (PWM呼吸灯)合泰开发板HT66F2390-----点灯大师
  • (博弈 sg入门)kiki's game -- hdu -- 2147
  • (二)windows配置JDK环境
  • (官网安装) 基于CentOS 7安装MangoDB和MangoDB Shell
  • (蓝桥杯每日一题)平方末尾及补充(常用的字符串函数功能)
  • (六) ES6 新特性 —— 迭代器(iterator)
  • (亲测有效)解决windows11无法使用1500000波特率的问题
  • (数据大屏)(Hadoop)基于SSM框架的学院校友管理系统的设计与实现+文档
  • (文章复现)基于主从博弈的售电商多元零售套餐设计与多级市场购电策略
  • (五)c52学习之旅-静态数码管