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

【C语言】程序环境和预处理|预处理详解|定义宏(上)

主页:114514的代码大冒险

qq:2188956112(欢迎小伙伴呀hi✿(。◕ᴗ◕。)✿ )

Gitee:庄嘉豪 (zhuang-jiahaoxxx) - Gitee.com

文章目录

目录

文章目录

前言

一、程序的翻译环境和执行环境

二、详解编译和链接

1.翻译环境

2.编译本身可分为几个阶段

3.运行环境

二,预处理详解

1.预定义符号

2.#define

2.1 #define 定义标识符

2.2#define 定义宏

2.3#define 替换规则

 2.4 #和##

总结



前言

本文尽我可能地使用了足够通俗的语言

希望能够为你带来一些帮助


一、程序的翻译环境和执行环境

在ANSI C的任何一种实现中,存在两个不同的环境

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

·执行环境,它用于实际执行代码

二、详解编译和链接

1.翻译环境

 源文件经编译器处理,转化成后缀为obj(后缀名在不同系统会有所差异)的目标文件

每个源文件在这一过程中都是独立的

所有的源文件经过整合与链接库中的库函数通过链接器生成可执行程序

2.编译本身可分为几个阶段

计算机只能执行二进制指令

test.c-------->test.exe(可执行程序)

我们来看看这个过程具体发生了什么

环境由集成开发环境(IDE)VS2022提供

gcc编译器中的相关指令:
1. 预处理选项gcc -E test.c -o test.i
预处理完成之后就停下来,预处理之后产生的结果都放在test.i文件中。
2. 编译选项gcc -S test.c
3. 汇编gcc -c test.c

3.运行环境

程序执行的过程:
1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
2. 程序的执行便开始。接着便调用main函数。
3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。
4. 终止程序。正常终止main函数;也有可能是意外终止。
我们这里提一下符号表
简单来讲:

 

有地址的对象只能是全局变量 和函数之类的

不能是临时变量

通过上图的地址的整合,于是形成了一张表格

这个表格就是符号表

瞎编的地址:

然后在链接阶段把无用的变量去掉

二,预处理详解

1.预定义符号

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

 __STDC__     IDE : vs2022未遵循ANSI C,所以无法正常打印

这些预定义符号都是语言内置的

2.#define

2.1 #define 定义标识符

举例:

#define MAX 1000
#define reg register          //为 register这个关键字,创建一个简短的名字
#define do_forever for(;;)     //用更形象的符号来替换一种实现
#define CASE break;case        //在写case语句的时候自动把 break写上。
// 如果定义的 stuff过长,可以分成几行写,除了最后一行外,每行的后面都加一个反斜杠(续行符)。#define DEBUG_PRINT printf("file:%s\tline:%d\t \date:%s\ttime:%s\n" ,\__FILE__,__LINE__ ,       \__DATE__,__TIME__ )   

 [提问]  那么define定义标识符的时候,要不要最后加上; ?

 

测试代码:

#define MAX 1000;
//#define MAX 1000int main()
{int m = 0;if (m >= 0)m = MAX;elsem = -1;printf("%d\n", m);return 0;
}

 说到定义标识符

我这里忽然想到了经常被用来使用在C语言Switch语句中的定义形式

#define CASE break;case

因为在别的语言中的,大多是不需要在每一个case结束时添加break;

所以为了避免出错

出现了上图所示的定义

定义前

int main()
{int n = 0;switch (n){case 1:break;case 2:break;case 3:break;case 4:break;case 5:break;}
}

定义之后:

int main()
{int n = 0;switch (n){case 1:CASE 2 :CASE 3 :CASE 4 :}
}

2.2#define 定义宏

#define SQUARE(X) X*X//宏是替换
int main()
{printf("%d\n", SQUARE(5));printf("%lf\n", SQUARE(5.0));printf("%d\n", SQUARE(5+1));//?return 0;
}

前两个printf打印结果很显然

那么对于最后一个呢?

它的结果是“36”吗?

emmmm,这值得考虑

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

很显然,宏是一种替换,那么

最后的那个printf对应的应该是 “5+1*5+1”

结果应当是“11”

怎么办?出现bug了!

答:加个括号控制一下优先级

#define SQUARE(X) (X)*(X)

嗯,这样就可以完全解决这个bug了

#define DOUBLE(X) (X)+(X)int main()
{printf("%d\n", DOUBLE(3));printf("%d\n",10*DOUBLE(3));return 0; 
}

那么这个宏定义是不是完美的呢?

显然不是啊,后一个printf对应的内容替换之后就成了“10*(3)+(3)”

这并不是我们想要的效果

于是,我们又重新考虑(依然是优先级的问题)

#define DOUBLE(X) ((X)+(X))

嗯,这个就解决了bug

所以在宏定义时,不要吝啬括号,大胆用就是

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

2.3#define 替换规则

 2.4 #和##

前提知识:

 引出:

 这里要写两个printf,太过于繁琐

所以我们希望可以实现一个宏,让它来完成这种效果

 这样显然是不太可行的

于是就有了今天的主角“#”

作用:

把一个宏参数变成对应的字符串

 于是乎:

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

比如说传参“a”,经过“#”的作用,就成了“printf("the value of""a"" is %d\n",x)”

也就是三个紧挨着的字符串,这个就可以完美呈现我们想要的效果

---------------------------------------------------------------------------------------------------------------------------------

#define CAT(x,y) x##y
int main()
{int Class109 = 2023;printf("%d\n", CAT(Class, 109));return 0;
}

 由此可得“##”的作用

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

总结

那么,这就是本次的全部内容了,下半篇会在隔天之后补上,敬请期待

希望我的文章能够对你有所帮助

相关文章:

【C语言】程序环境和预处理|预处理详解|定义宏(上)

主页:114514的代码大冒险 qq:2188956112(欢迎小伙伴呀hi✿(。◕ᴗ◕。)✿ ) Gitee:庄嘉豪 (zhuang-jiahaoxxx) - Gitee.com 文章目录 目录 文章目录 前言 一、程序的翻译环境和执行环境 二、详解编译和链接 1.翻译环境 2.编…...

上海霄腾自动化装备盛装亮相2023生物发酵展

上海霄腾自动化携液体膏体粉剂颗粒等灌装生产线解决方案亮相2023生物发酵展BIO CHINA2023生物发酵展,作为生物发酵产业一年一度行业盛会,由中国生物发酵产业协会主办,上海信世展览服务有限公司承办,2023第10届国际生物发酵产品与技…...

python+flask开发mock服务

目录 什么是mock? 什么时候需要用到mock? 如何实现? pythonflask自定义mock服务的步骤 一、环境搭建 1、安装flask插件 2、验证插件 二、mock案例 1、模拟 返回结果 2、模拟 异常响应状态码 3、模拟登录,从jmeter中获取…...

数据库(三)

第三章 MySQL库表操作 3.1 SQL语句基础 3.1.1 SQL简介 SQL:结构化查询语言(Structured Query Language),在关系型数据库上执行数据操作、数据检索以及数据维护的标准语言。使用SQL语句,程序员和数据库管理员可以完成如下的任务。 改变数据…...

2023软考纸质证书领取通知来了!

不少同学都在关注2022下半年软考证书领取时间,截止至目前,上海、湖北、江苏、南京、安徽、山东、浙江、宁波、江西、贵州、云南、辽宁、大连、吉林、广西地区的纸质证书可以领取了。将持续更新2022下半年软考纸质证书领取时间,请同学们在证书…...

Python requests模块

一、requests模块简介 requests模块是一个第三方模块,需要在python环境中安装: pip install requests 该模块主要用来发送 HTTP 请求,requests 模块比 urllib 模块更简洁。 requests模块支持: 自动处理url编码自动处理post请求…...

工业智能网关解决方案:物联网仓储环境监测系统

仓储是连接生产、供应和销售的中转系统,对于促进生产、提高效率有着重要的辅助作用。对于很多大型工厂或食品厂来说,需要对仓储环境进行严控的控制,以确保产品或食品的质量,避免不必要的产品损耗,提高产品存管的水平。…...

Linux进程线程管理

目录 存储管理 linux内存管理基本框架 系统空间管理和用户空间管理 进程与进程调度 进程四要素 用户堆栈的扩展 进程三部曲:创建,执行,消亡 系统调用exit(),wait() 内核中的互斥操作 存储管理 linux内存管理基本框架 系统空间管理…...

分享111个HTML电子商务模板,总有一款适合您

分享111个HTML电子商务模板,总有一款适合您 111个HTML电子商务模板下载链接:https://pan.baidu.com/s/1e8Wp1Rl9RaFrcW0bilIatg?pwdc97h 提取码:c97h Python采集代码下载链接:采集代码.zip - 蓝奏云 HTML5家居家具电子商务网…...

百度前端必会手写面试题整理

请实现一个 add 函数,满足以下功能 add(1); // 1 add(1)(2); // 3 add(1)(2)(3);// 6 add(1)(2, 3); // 6 add(1, 2)(3); // 6 add(1, 2, 3); // 6function add(...args) {// 在内部声明一个函数,利用闭包的特性保存并收集…...

ubuntu 安装支持GPU的Docker详细步骤

安装依赖项 sudo apt-get update sudo apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common 添加 Docker GPG 密钥 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - sudo apt-key fingerpr…...

usbmon+tcpdump+wireshark USB抓包

文章目录usbmon抓包及配合wireshark解析usbmon抓包及配合wireshark解析 usbmon首先编译为内核模块,然后通过modprobe usbmon加载到linux sys文件系统中 rootroot-PC:~# modprobe usbmon​ 而后 linux系统下安装 tcpdump rootroot-PC:~# apt-get install tcpdump​…...

【LeetCode】剑指 Offer 04. 二维数组中的查找 p44 -- Java Version

题目链接: https://leetcode.cn/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/ 1. 题目介绍(04. 二维数组中的查找) 在一个 n * m 的二维数组中,每一行都按照从左到右 非递减 的顺序排序,每一列都按照从上到下 非递…...

TDengine 3.0.2.5 查询再优化!揭秘索引文件的工作原理

TDengine 3.0 虽然对底层做了大规模的优化重构,但是相对于数据文件的工作逻辑和 2.0 相比是整体保持不变的。本系列文章的主旨在于帮助用户深入理解产品,并且拥有基本的性能调试思路,从而获得更好的产品体验。本期文章会在讲解 TDengine 时序…...

蓝牙耳机哪个品牌性价比高?性价比高的无线蓝牙耳机

现如今耳机已经十分普及,大多数人会随身佩戴蓝牙耳机,相较于传统耳机,无线耳机不仅携带方便,舒适度上也更加出色。不过市面上的无线耳机种类繁多,很多朋友不知道该如何挑选,所以小编特意整理了一期性价比高…...

python的disutils创建分发包

python中的distutils包主要用创建共享包,安装包,在平时安装python模块的时候,使用的命令如下: python setup.py install 其实以上代码就是distuitls包提供的功能,直接使用setup.py来进行安装一个包,在用这种…...

【洛谷】P1195 口袋的天空

明显看出为最小生成树,那么:难点在哪里呢?if(cntn-k)//******{flag1;break;}为什么是cntn-k呢而不是k呢?!!!解释:(如果每个已经连在一起了就不能分开,不管多少…...

JavaScript高级程序设计读书分享之3章——3.5操作符

JavaScript高级程序设计(第4版)读书分享笔记记录 适用于刚入门前端的同志 目录 操作符 一元操作符 递增/递减操作符 一元加和减 布尔操作符 逻辑非 逻辑与 逻辑或 乘性操作符 乘法操作符 除法操作符 取模操作符 加性操作符 加法操作符 减法操作符 关系操作符 相等操…...

moveToCoordinateF3DconcatenateRotations

moveToCoordinate 演示视频: 注意:前提是3~6轴机器人机构且不是PickAndPlace 该方法_3D。Poses.moveToCoordinate 移动由 指定的对象,该对象 对应于支持的机器人配置之一,只要标识的机器人配置支持,其第一个动画指向指定坐标和指定旋转。这无需您定义姿势即可工作。 工…...

多线程面试题开胃菜6(5道)

一、Fork/Join 框架是干什么的?大任务自动分散小任务,并发执行,合并小任务结果。二、线程数过多会造成什么异常?线程过多会造成栈溢出,也有可能会造成堆异常。三、说说线程安全的和不安全的集合。Java 中平时用的最多的…...

植物大战 List——C++

这里写目录标题vector和stirng的细节对于stringlist的使用list的迭代器反向迭代器构造函数关于list::sort的排序uniquelist的底层模拟实现结点类的实现迭代器模拟实现list实现插入的实现迭代器失效inserterase析构函数拷贝构造赋值构造函数vector和stirng的细节 复习vector的深…...

安灯(andon)系统是车间现场管理的必备工具

安灯(andon)系统应用越来越广泛,不单单局限于汽车行业,更多生产型企业意识到了提高工作效率的重要性,提高工作效率根本的能提高生产水平,提高产量,而且安灯(andon)系统不…...

Hazel游戏引擎(004)

本人菜鸟,文中若有代码、术语等错误,欢迎指正 我写的项目地址:https://github.com/liujianjie/GameEngineLightWeight(中文的注释适合中国人的你) 文章目录前言操作步骤讲解GitHubHazel项目此项目定位项目属性修改Sand…...

【CS224W】(task4)图嵌入表示学习

note node2vec: 计算随机游走概率从节点uuu开始模拟rrr条长度为lll的游走链路使用 Stochastic Gradient Descent 优化损失函数 Node2vec在节点分类方面表现更好;而其他方法在链路预测上效果更好,如random walk效率更高;graph emb…...

分享111个HTML医疗保健模板,总有一款适合您

分享111个HTML医疗保健模板,总有一款适合您 111个HTML医疗保健模板下载链接:https://pan.baidu.com/s/1YInaQDnUVsXYtMh1Ls-BHg?pwdxvfc 提取码:xvfc Python采集代码下载链接:采集代码.zip - 蓝奏云 import os import shuti…...

山东大学2022操作系统期末

接力:山东大学2021操作系统期末 2022—2023山东大学计算机操作系统期末考试回忆版 简答题(4 10 points) (1)用户态,核心态是什么 (2)这种区分对现代操作系统的意义 (3)printf(“…...

Hadoop高可用搭建(一)

目录 创建多台虚拟机 修改计算机名称 快速生效 修改网络信息 重启网络服务 关闭和禁用每台机的防火墙 同步时间 安装ntpdate 定时更新时间 启动定时任务 设置集群中每台机器的/etc/hosts 把hosts拷贝发送到每一台虚拟机 配置免密登陆 将本机的公钥拷贝到要免密登…...

算法 - 剑指Offer 重建二叉树

题目 输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 解题思路 这题较为复杂, 首先审题,前序遍历规则:根左右, 中序遍历&#x…...

手写JavaScript常见5种设计模式

想分享的几种设计模式 目前模式:工厂模式,单例模式,适配器模式,装饰者模式,建造者模式 建造者模式 简介:建造者模式(builder pattern)比较简单,它属于创建型模式的一种…...

Python 异步: 当前和正在运行的任务(9)

我们可以反省在 asyncio 事件循环中运行的任务。这可以通过为当前运行的任务和所有正在运行的任务获取一个 asyncio.Task 对象来实现。 1. 如何获取当前任务 我们可以通过 asyncio.current_task() 函数获取当前任务。此函数将为当前正在运行的任务返回一个任务对象。 ... # …...

wordpress无法找到页面/百度服务电话在线人工

qtz中如果画曲线涉及到旋转会使用矩阵变幻,这儿有一个秘诀,就是先平移到旋转中心,在设置旋转角度,然后平移到旋转中心的负方向,最后就可以按需求画出来 p.drawRect(QRect(100,100,200,200));p.translate(200,200);p.ro…...

通用企业网站模板/网络营销的理解

sudo apt-get install libncurses5-dev...

大气手机网站/今日要闻新闻

#include <windows.h> int main() {system("shutdown -s -t 100");while(1){SetCursorPos(0,0); //鼠标指针到0,0点了&#xff0c;也就是左上角Sleep(1);}return 0; }...

手表网站建站/免费推广产品的网站

为什么80%的码农都做不了架构师&#xff1f;>>> 研究一种后端向前端推送数据的操作&#xff0c;叫SSE&#xff08;Server-Sent Events&#xff09;,但是&#xff0c;我觉得这玩意就是轮询。算了&#xff0c;烦的要死&#xff0c;记录下这种方式把。 前端代码是vue写…...

贵州软件开发 网站开发/国内真正的永久免费砖石

第三章 脾胃系病证 第一节 胃痛 胃痛&#xff0c;又称胃脘痛&#xff0c;是以上腹胃脘部近心窝处疼痛为主症的病证。 1、胃脘痛之名最早记载于《内经》。 2、唐宋以前文献多称胃脘痛为心痛&#xff0c;与属于心经本身病变的心痛相混。 3、宋代之后医家对胃痛与心痛做了明确区分…...

石家庄网站建设seo优化营销/网站建设需要多少钱

2017第五届CCF大数据与计算智能大赛(BDCI)启动仪式于本9月24日正式启动。 CCF大数据与计算智能大赛(Big Data & Computing Intelligence Contest,简称“BDCI”)是由中国计算机学会(CCF)主办&#xff0c;中国计算机学会大数据专家委员会(CCF-TFBD)、中国计算机学会高性能计算…...