程序环境、预处理和宏

news2024/11/16 15:45:14

 前言:

目录

一、程序的翻译环境

二、运行环境

三、预处理 

1.预处理上的文本操作

Ⅰ注释的删除

 Ⅱ头文件的包含

Ⅲ#define的替换

2.预定义符号 

3.#define

Ⅰ #define 定义标识符

Ⅱ #define 定义宏

Ⅲ #define 替换规则

Ⅳ #和##

四、宏和函数的区别

1.宏和函数的区别

 2.#undef

3.条件编译

4.文件包含

5.嵌套文件包含


首先程序环境中有两种不同的环境:

翻译环境:在这个环境中源代码被转换为可执行的机器指令

执行环境:用于实际执行代码

一、程序的翻译环境

 翻译环境又分为 编译 和 链接

组成一个程序的每个源文件通过编译过程分别转换成目标代码(object )。
每个目标文件由链接器(linker)捆绑在一起,形成一个单一而完整的可执行程序(二进制程序)。
链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人
的程序库,将其需要的函数也链接到程序中 

二、运行环境

C语言的运行环境指的是能够运行C语言程序的必要条件,包括操作系统、编译器、链接器、库等

三、预处理 

预处理是翻译环境中编译上的预处理(也叫做预编译),预处理上回进行一些文本操作:注释的删除(替换为空格)、#include 头文件的包含 、#define符号的替换。接下来就用代码来说明一下

1.预处理上的文本操作

Ⅰ注释的删除

 接着我们来继续打开test.i的文件

 Ⅱ头文件的包含

Ⅲ#define的替换

2.预定义符号 

 注意:预定义符号都是语言内置的

__FILE__  进行编译的源文件

__LINE__  文件当前行号

__DATE__  文件被编译的日期

__TIME__  文件被编译的时间

__STDC__  如果编译器遵循ANSI C,其值为1,否则未定义

例如

#include<stdio.h>
int main() 
{
	int a = 0;
	printf("%s\n%d\n%s",__FILE__,__LINE__,__TIME__);
	return 0;
}

3.#define

Ⅰ #define 定义标识符

例如

注意 #define MAX 6 后面最好不要加分号,容易出错
 

Ⅱ #define 定义宏

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

宏的格式

#include<stdio.h>

#define ADD(X,Y) ((X)+(Y))
int main() 
{
	int a = 3;
	int b = 2;
	printf("%d",ADD(a,b));
	return 0;
}

 打印结果

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

Ⅲ #define 替换规则

在进行#define 定义符号和宏时  有以下步骤:

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

注:宏,不能出现递归;

Ⅳ #和##

我们平时可能会有这样的问题:如何把参数插入到字符串中?

#include<stdio.h>
int main() 
{
	char* p = "hello""world!";
	printf("hello""world!\n");
	printf("%s",p);
	return 0;
}

 字符串是有自动连接的特点的

#include<stdio.h>
#define PRINT(FORMAT,VALUE) printf("the var is "FORMAT"",VALUE)
int main()
{
	PRINT("%d",10);
	return 0;
}

 

 只有当字符串作为宏参数的时候才可以把字符串放在字符串中

使用# 可以把一个宏参数变成字符串

#include<stdio.h>
#define PRINT(FORMAT,VALUE) printf("the var of " #VALUE " is " FORMAT "\n",VALUE)
int main()
{
	int a = 10;
	PRINT("%d", 5+a);
	return 0;
}

##的作用

##可以把位于它两边的符号合成一个符号

#include<stdio.h>
#define ADD_SUM(NAME,VALUE) (s##VALUE +=3) 
int main() 
{
	int s = 0;
	int s3 = 0;
	printf("s3: %d\n",s3);

	printf(" s: %d\n",ADD_SUM(s,3));

	printf("s3: %d\n",s3);
	return 0;
}

解析

注意  连接必须产生一个合法的标识符。否则其结果就是未定义的

四、宏和函数的区别

1.宏和函数的区别

 刚开始学C语言的时候很多人会发现宏和函数好像

宏,通常被应用于执行简单的运算

例如 比较两个数的大小 

#define MAX(X,Y) ((X)>(Y)?(X):(Y))

可能你回想为什么不用函数呢?

其实

  • 调用函数涉及函数的栈帧调用,所用的时间比较多,所以说使用宏在程序的规模和速度要比函数好一些
  • 函数的参数必须声明为特定的类型,宏是类型无关的
  • 宏的参数可以是类型,而函数是不可以的

宏也有一些缺点

  • 如果代码比较长,宏会增加程序的长度
  • 宏是不方便调试的
  • 宏会涉及到一些优先级的问题
  • 宏是与类型无关的,不是很严谨

小建议:宏名尽量使用大写字母

 2.#undef

用于移除一个宏定义 

#undef NAME
//如果现存的一个名字需要被重新定义,那么它的旧名字首先要被移除

3.条件编译

我们在按住键盘的Ctrl 然后在点击头文件,会发现

会看到这些。

上图中的就是 条件编译

 在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃是很方便的。因为我们有 条件编译指令。

【例】调试性的代码,删除可惜,保留又碍事,所以我们可以选择性的编译

#include<stdio.h>
int main() 
{
	int a = 10;
	int b = a;
	//下方我们使用条件编译一下,查看赋值是否成功
#if 1
	printf("%d",b);
#endif
	return 0;
}

这里的 #if 就相当于 条件判断

#if是条件编译指令的关键字,可以根据条件判断是否编译某段代码。在编译预处理阶段,预处理器会根据#if后的条件判断语句的真假来决定是否编译接下来的代码。如果条件为真,则编译接下来的代码,否则忽略不编译

#endif 表示结束

#endif是C/C++中的一种预处理指令,表示条件编译的结束。它通常与#if或#ifdef一起使用,用于控制在编译时是否包含某段代码。如果#if或#ifdef指令中的条件为真,则编译区间代码,直到遇到#endif指令结束。

#ifndef  

#ifndef 是一个预处理指令,表示如果指定的标识符已经被定义过了,则跳过后续的代码,否则执行后续的代码。在C/C++中,通常用来防止头文件被重复包含,因为头文件中可能包含全局变量、宏定义和函数声明等内容,多次包含会导致编译错误或运行时错误。因此,在头文件中一般都会使用#ifndef指令来避免重复包含。如果头文件被重复引入,会导致重复定义全局变量或函数,导致编译错误或者出现未知错误

所以使用条件编译可以避免头文件被重复引入 

#include<stdio.h>
#define A 100
int main() 
{
	int a = 10;
	int b = a;
#ifndef A
	printf("A is not defined\n");
#endif 

#ifndef B
	printf("B is not defined\n");
#endif

#ifdef A
	printf("A is defined\n");
#endif
	return 0;
}

4.文件包含

当涉及多个代码文件时,我们就会使用头文件

很多人对于 #include <test.h>  和#include "test.h" 有疑问

首先 #include 指令可以使另外一个文件被编译

在使用 #include <test.h>

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

 使用 #include "test.h"

本地文件包含, 查找策略:先在源文件所在目录下查找,如果该头文件未找到,编译器就像查找库函数头文件一样在标准位置查找头文件

5.嵌套文件包含

使用条件编译可以避免头文件的重复使用,这可以提高效率

上述就是对程序环境、预处理和宏简单地介绍了一下,后续还会补充滴

 

加油! 

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

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

相关文章

一文浅析Linux 中断处理

1. 中断的概念 中断是指在CPU正常运行期间&#xff0c;由于内外部事件或由程序预先安排的事件引起的 CPU 暂时停止正在运行的程序&#xff0c;转而为该内部或外部事件或预先安排的事件服务的程序中去&#xff0c;服务完毕后再返回去继续运行被暂时中断的程序。Linux中通常分为…

东方通部署vue项目

在东方通中部署vue项目需要以war 的形式进行部署具体操作步骤如下 1. 正常打包完vue 项目 在其项目目录下创建WEB-INF 文件夹&#xff0c;同时在里面新建一个 rewrite.config 的文件文件具体内容如下&#xff1a; RewriteRule ^/index\.html$ - [L]RewriteCond …

【树莓派图像处理】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、Qt OPENCV 安装测试&#xff1f;运行Qt错误 二、使用步骤1.框架1. 开启摄像头2.获取显示图像的内容 2.测试 总结 前言 提示&#xff1a;这里可以添加本文要…

uniapp 测试 app 到安卓模拟器部署方法以及常见错误解决 无废话

uniapp 测试 app 到安卓模拟器 1.1 安装安卓模拟器 https://www.yeshen.com/ 1.2 查看安装模拟器端口 右击夜神模拟器属性打开文件位置 在打开的文件夹找到 debugReport 双击运行查看运行出来的端口号 一般都是&#xff1a;62001 1.3 HBuilder 配置 选中项目运行运行到手机…

TSINGSEE青犀AI智能分析算法助力小区规范整改:楼道杂物堆放检测

小区楼道属于公共消防通道&#xff0c;是小区居民出行的唯一通道&#xff0c;但由于物业管理不到位或业主个人素质问题&#xff0c;经常存在在楼梯间堆放杂物的问题&#xff0c;严重影响居民日常出行&#xff0c;也增加了楼道消防安全隐患。为做到彻底解决小区楼道堆积杂物问题…

Python数据挖掘实用案例——自动售货机销售数据分析与应用

&#x1f680;欢迎来到本文&#x1f680; &#x1f349;个人简介&#xff1a;陈童学哦&#xff0c;目前学习C/C、算法、Python、Java等方向&#xff0c;一个正在慢慢前行的普通人。 &#x1f3c0;系列专栏&#xff1a;陈童学的日记 &#x1f4a1;其他专栏&#xff1a;CSTL&…

即使密码正确,App Store可能也会不断询问密码,那么如何修复呢

当你从app Store购买并安装应用程序时,你需要使用Apple ID和密码登录以确认你的帐户。然而,许多iOS用户面临的情况是,无论他们输入多少次,App Store都会不断要求输入密码。你的iPhone是否也会不断提示你输入密码? 事实上,即使你输入了好几次正确的密码,App Store也会不…

Java,利用switch的穿透

题目&#xff1a;输入2023年的月份和天数&#xff0c;求这一天是2023年的第几天&#xff0c;switch实现。 在switch语句中&#xff0c;case就是一个入口&#xff0c;表达式与case后面的表达式匹配上后&#xff0c;就进入后面的语句&#xff0c;其他case后面的语句也会进入执行&…

QTday03(信号与槽、对话框)

今日任务&#xff1a; 1. 完善对话框&#xff0c;点击登录对话框&#xff0c;如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出提示”登录成功“&#xff0c;提供一个Ok按钮&#xff0c;用户点击Ok后&#xff0c;关闭登录界面&#xff0c;跳转到新的界面中 …

算法通关村第一关-链表黄金挑战环形链表问题

环形链表 描述 : 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 LeetCode 141.环形链表 : 141. 环形链表 牛客 BM6 判断链表中是否有 : 分析 : 方法一…

2023年下半年软考考试重磅消息

重磅消息一&#xff1a;科目连考&#xff0c;分批考试 2023年下半年软考考试&#xff0c;采取科目连考、分批次考试的方式。 什么是科目连考&#xff1f; 连考就是第一个科目作答结束交卷完成后&#xff0c;自动进入第二个科目的考试&#xff0c;第一个科目剩余的时长可为第二…

2023年10月【考试战报】|ORACLE OCP 19C考试通过

【考试战报】ORACLE OCP 19C考试通过_oracle19c ocm认证_厦门微思网络的博客-CSDN博客 自OCP认证进入中国以来&#xff0c;越来越被大多数DBA所认可&#xff0c;也越来越被企业所重视&#xff0c;90%以上DBA深造&#xff0c;都会选择OCP认证。Oracle开始在中国挂起新一轮的OCP认…

jmeter集成kafka测试

Kafka的使用 查看kafka的topic ./kafka-topics --bootstrap-server 10.1.9.84:9092 --list 查看topic信息 ./kafka-topics --bootstrap-server 10.1.9.84:9092 --describe --topic topic_example_1 创建topic 创建topic名为test&#xff0c;分区数为8&#xff0c;副本数为…

性能监控软件是什么?有哪些优势?

在现代科技驱动的世界中&#xff0c;计算机系统的性能对于企业和个人用户都至关重要。性能监控软件是一种不可或缺的工具&#xff0c;可以帮助我们实时跟踪、分析和优化系统的性能。本文将介绍性能监控软件的概念、其重要性以及如何选择和使用这些工具来提高系统效率。 一、性能…

气膜建筑是真正的节能环保建筑

气膜结构建筑是用特殊的PVC膜材做外壳&#xff0c;配备一套智能化的机电设备在智能环保气膜内部提供空气的正压&#xff0c;即依靠内外气压差来支撑整个气膜结构受力的建筑。智能环保气膜内部无需任何框架或梁柱支撑&#xff0c;没有受弯、受扭和受压的构件&#xff0c;跨度可以…

【Javascript保姆级教程】运算符

文章目录 前言一、运算符是什么二、赋值运算符2.1 如何使用赋值运算符2.2 示例代码12.3 示例代码2 三、自增运算符3.1 运算符3.2 示例代码13.3 示例代码2 四、比较运算符4.1 常见的运算符4.2 如何使用4.3 示例代码14.4 示例代码2 五、逻辑运算符逻辑运算符列举 六、运算符优先级…

微信小程序进阶——会议OA其他界面

目录 一、自定义tabs组件应用 1.1 创建自定义组件 1.1.1 新建自定义组件存放目录components 1.1.2 工具检查报错解决 1.1.3 编写组件模板 1.1.3 定义组件模板属性 1.1.4 加入组件样式 1.2 使用自定义组件 1.2.1 引用声明 1.2.2 组件传参 二、其他界面的布局 2.1 会…

半球体容器漏水体积微分问题

问题&#xff1a;半球体的容器中盛满水&#xff0c;容器底部有一个小孔&#xff0c;水从小孔流出。给出水体积的变化量 V 随水面高度 h 变化的微分关系式。 在微小的时间间隔 [ t , t d t ] [t, t\mathrm{d}t] [t,tdt] 内&#xff0c;水面高度由 h h h 降至 h d h , ( d h…

官媒代运营:如何将内容营销做到深入人心

生活中&#xff0c;信息传递和有效的沟通是我们与世界互动的重要方式&#xff0c;而语言是这种互动的关键媒介。然而&#xff0c;在营销界&#xff0c;我们已经迈出了更深一步&#xff0c;将语言与内容相结合&#xff0c;以创造内容营销这一强大的战略工具。内容&#xff0c;作…

35岁失业程序员的在线简历制作工具

失业在家&#xff0c;实在是难熬&#xff0c;人过了35面试的机会很少&#xff0c;而且大多数都是外包&#xff0c;可能大环境也是一个原因吧&#xff0c;这不也没闲着&#xff0c;写了个在线制作简历的工具&#xff0c;帮助大家更好的找工作吧&#xff0c; 废话不多说先看看效…