【C进阶】C程序是怎么运作的呢?-- 程序环境和预处理(上)
前言:
由于c语言的程序编译链接的这块知识点不清楚,回来复习一遍,以便于好理解c++知识,我会尽快更新下一篇文章。
目录
1.程序的翻译环境和执行环境
2.翻译环境(编译+链接)
编译(编译器)
预编译(预处理)
1.头文件的包含
2.注释的测试
编译过程
汇编过程
链接
1.合并段表
2.符号表的合并和重定位
计算机语言的发展
运行环境(翻译之后)
3.预处理详解
3.1 预定义符号
3.2 #define
3.2.1 #define 定义标识符
3.2.2 #define 定义宏
3.2.3#define 替换规则
3.2.4 #和##
3.2.5 带副作用的宏参数
1.程序的翻译环境和执行环境
总体过程:

在ANSI C的任何一种实现中,存在两个不同的环境
第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。
第2种是执行环境,它用于实际执行代码。
2.翻译环境(编译+链接)
我们常说一个test.c文件要经过以下步骤才能产生可执行的程序,那么具体是怎么做到的呢?

在vs编译器上是要经过以下过程的:

源文件和目标文件的关系:

VS是一个集成开发环境,集成很多的功能ctr1+F5,不方便观察每个细节的功能接下来,我使用gcc这个编译器给大家演示

由于上图的操作把这个编译运行的步骤一次走完了,我们一步步来,咱们用指令让程序停在预编译的阶段:

编译(编译器)
预编译(预处理)
将控制台的内容放到test.i之后,预处理阶段所做的事情:
1.头文件的包含

2.注释的测试

编译过程
功能:把C语言代码翻译成汇编代码
1.语法分析
2.词法分析
3.语义分析
4.符号汇总函数名,全局变量, 不会汇总 局部变量(函数运行起来才行)![]()
链接:https://pan.baidu.com/s/1cVcZRTj772hJXm0mO0Q_cw?pwd=1234
提取码:1234
汇编过程
1.把汇编代码转换成二进制的指令

2.形成符号表

链接
1.合并段表
2符号表的合并和重定位
1、2的作用其实是在链接期间为这种跨文件的代码进行协作的时候起作用的。
在vscode中操作:

过程:

1.合并段表

2.符号表的合并和重定位
把无效的地址给替换掉,符号表和段表的关系是:符号表是段表的内容

那该如何体现这个作用呢?
假设我们在test.c文件底下extern了一个函数Add,但是在add.c底下没有实现这个Add函数,就会输出以下错误(链接型错误)

如果说这个函数写错的话,在main函数内调用大写的,但是在add.c内定义成小写的,是依然找不到

计算机语言的发展

运行环境(翻译之后)
1. 程序必须载入 内存 中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。2. 程序的执行便开始。接着便调用 main 函数(main函数第一行开始)3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈( stack )-- 函数栈帧 ,存储函数的局部变量和返回地址。 程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。4. 终止程序。正常终止 main 函数;也有可能是意外终止。
3.预处理详解
3.1 预定义符号
__FILE__ //进行编译的源文件__LINE__ //文件当前的行号__DATE__ //文件被编译的日期__TIME__ //文件被编译的时间
执行:

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

而放在gcc编译器上面是可以执行通过的:

编译器在代码编译的时候,会对函数和变量名重命名的,C++ 中会更加复杂
在C语言中重命名的规则基本就是:加_

3.2 #define
3.2.1 #define 定义标识符
语法:#define name stuff
全部例子:
#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 MAX 1000
#define reg register//为 register这个关键字,创建一个简短的名字

#define do_forever for(;;)//用更形象的符号来替换一种实现

#define CASE break;case //在写case语句的时候自动把 break写上。
长行如何拆分,\后面只能是换行,不能是其他
如果定义的 stuff过长,可以分成几行写,除了最后一行外,每行的后面都加一个反斜杠(续行符)。
在define定义标识符的时候,要不要在最后加上 ; ?
#define MAX 1000;#define MAX 1000
if ( condition )max = MAX ;elsemax = 0 ;
这里会出现语法错误.
3.2.2 #define 定义宏
#define name( parament-list ) stuff其中的 parament - list 是一个由逗号隔开的符号表,它们可能出现在 stuff 中
#define SQUARE( x ) x * x
SQUARE ( 5 );
5 * 5
int a = 5 ;printf ( "%d\n" , SQUARE ( a + 1 ) );
替换文本时,参数x被替换成a + 1,所以这条语句实际上变成了:printf ("%d\n",a + 1 * a + 1 );
#define SQUARE(x) (x) * (x)
printf ( "%d\n" ,( a + 1 ) * ( a + 1 ) );
#define DOUBLE(x) (x) + (x)

定义中我们使用了括号,想避免之前的问题,但是这个宏可能会出现新的错误。
int a = 5 ;printf ( "%d\n" , 10 * DOUBLE ( a ));
printf ("%d\n",10 * (5) + (5)); #define DOUBLE( x) ( ( x ) + ( x ) )
所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中的操作符或邻近操作符之间不可预料的相互作用。

所以这就涉及到#define的替换规则了
3.2.3#define 替换规则
在程序中扩展 #define 定义符号和宏时,需要涉及几个步骤。1. 在调用宏时,首先对参数进行检查,看看是否包含任何由 #define 定义的符号。如果是,它们首先被替换。2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。3. 最后,再次对结果文件进行扫描,看看它是否包含任何由 #define 定义的符号。如果是,就重复上述处理过程。
3.2.4 #和##
如何把参数(变量名)插入到字符串中?
首先我们看看这样的代码:
char* p = "hello ""bit\n";
printf("hello"" bit\n");
printf("%s", p);
这里输出的是不是hello bit ?

请看下图,有没有那么一条语句,将这三个变量传参传过去,然后实现它们各自的输出呢?

现在定义一个宏
#define print_format(num, format) \ printf("the value of #num is "format)
并且让它输出:

这时候发现需要正确输入它们的数值:


## 可以把位于它两边的符号合成一个符号。它允许宏定义从分离的文本片段创建标识符。
3.2.5 带副作用的宏参数
x + 1 ; //不带副作用x ++ ; //带有副作用

在vscode2019内调试一下:

想知道宏和函数的区别吗,欲知后事如何,请听下回分解。
相关文章:
【C进阶】C程序是怎么运作的呢?-- 程序环境和预处理(上)
前言: 由于c语言的程序编译链接的这块知识点不清楚,回来复习一遍,以便于好理解c知识,我会尽快更新下一篇文章。 目录 1.程序的翻译环境和执行环境 2.翻译环境(编译链接) 编译(编译器…...
点滴生活记录1
2023/10/10 今天骑小电驴上班,带着小鸭子一起。路上的时候,我给小鸭子说,你要帮我看着点路,有危险的时候提醒我,也就刚说完没几分钟,一个没注意,直接撞到一个拦路铁墩子上,车子连人歪…...
gitea仓库迁移
(1)先安装git,再直接将源机器上的gitea文件夹复制到新机器上。这样原始数据及账号信息都还在。 (2)根据实际情况修改gitea\custom\conf\app.ini文件夹下app.ini文件的相关路径。 (3)如下命令启…...
〖大前端 - 基础入门三大核心之JS篇㊽〗- BOM特效开发
说明:该文属于 大前端全栈架构白宝书专栏,目前阶段免费,如需要项目实战或者是体系化资源,文末名片加V!作者:哈哥撩编程,十余年工作经验, 从事过全栈研发、产品经理等工作,目前在公司…...
【扩散模型】ControlNet从原理到实战
ControlNet从原理到实战 ControlNet原理ControlNet应用于大型预训练扩散模型ControlNet训练过程ControlNet示例1 ControlNet与Canny Edge2. ControlNet与Depth3. ControlNet与M-LSD Lines4. ControlNet与HED Boundary ControlNet实战Canny Edge实战Open Pose 小结参考资料 Cont…...
AI并行计算:CUDA和ROCm
1 介绍 1.1 CUDA CUDA(Compute Unified Device Architecture)是Nvidia于2006年推出的一套通用并行计算架构,旨在解决在GPU上的并行计算问题。其易用性和便捷性能够方便开发者方便的进行GPU编程,充分利用GPU的并行能力࿰…...
2023五岳杯量子计算挑战赛数学建模思路+代码+模型+论文
目录 计算力网络(CPN)是一种新型的信息基础设施,完整论文代码见文末 问题描述 2.1 问题1 2.2 问题2 2.3 问题3 问题1的解答过程: 问题3的解答过程: 决策优化应用场景:人工智能模型超参数调优 背景信…...
生信数据分析高效Python代码
1. Pandas glob获取指定目录下的文件列表 import pandas as pd import globdata_dir "/public/data/" # 获取文件后缀为.txt的文件列表 df_all pd.concat([pd.read_csv(f, sep\t) for f in glob.glob(data_dir *.txt)]) print(df_all)2. 使用 enumerate 函数获取…...
Spring Kafka常用配置详解
目录 前言producer配置consumer 配置listener 配置 前言 在 Spring Kafka 中,主要的配置分为三大块,分别是producer、consumer、listener,下面我们就按模块介绍各个模块的常用配置 producer配置 在 Spring Kafka 中,spring.kaf…...
跨域的多种方案详解
浏览器的同源策略是为了保护用户的安全,限制了跨域请求。同源策略要求请求的域名、协议和端口必须完全一致,只要有一个不同就会被认为是跨域请求。 本文列举了一些处理跨域请求的解决方案: JSONPCORS跨域资源共享http proxynginx反向代理web…...
Java / Scala - Trie 树简介与应用实现
目录 一.引言 二.Tire 树简介 1.树 Tree 2.二叉搜索树 Binary Search Tree 3.字典树 Trie Tree 3.1 基本概念 3.2 额外信息 3.3 结点实现 3.4 查找与存储 三.Trie 树应用 1.应用场景 2.Java / Scala 实现 2.1 Pom 依赖 2.2 关键词匹配 四.总结 一.引言 Trie 树…...
JS/jQuery 获取 HTTPRequest 请求标头?
场景:在jquery封装的ajax请求中,默认是异步请求。 需要定一个秘钥进行解密,所以只能存放在请求头中。然后需要值的时候去请求头中读取。 注意:dataType设置,根据请求参数的格式设置,如果是加密字符串&…...
Leetcode—2034.股票价格波动【中等】
2023每日刷题(五十二) Leetcode—2034.股票价格波动 算法思想 实现代码 class StockPrice { public:int last 0;multiset<int> total;unordered_map<int, int> m;StockPrice() {}void update(int timestamp, int price) {if(m.count(time…...
【Linux】diff命令使用
diff命令 是一个用于比较两个文件或目录之间差异的命令。它可以显示两个文件之间的行级别差异,并以易于阅读的格式输出结果。 著者 由保罗艾格特、迈克海特尔、大卫海耶斯、理查德史泰尔曼和Len Tower撰写。 diff命令 -Linux手册页 语法 diff [选项] [文件1]…...
讯飞星火认知大模型与软件测试结合,提升软件质量与效率
随着人工智能技术的不断发展,越来越多的企业开始将其应用于软件开发过程中。其中,讯飞星火认知大模型作为一种基于深度学习的自然语言处理技术,已经在语音识别、机器翻译、智能问答等领域取得了显著的成果。而在软件测试领域,讯飞…...
【Flink on k8s】- 4 - 在 Kubernetes 上运行容器
目录 1、准备 k8s 集群环境、Docker 环境 2、启用 kubernetes 2.1 查询 k8s 集群基本状态...
软件重装或系统重装后避免重复踩坑
1. Office软件的坑在于字体又没了 Word字体库默认没有仿宋_GB2312和楷体仿宋_GB2312,需要手动添加。 提供如下两个下载链接,亲测有效: 仿宋_GB2312 楷体_GB2312 安装步骤:解压-复制.ttf文件至C:\Windows\Fonts 持续更新贴~...
【Jmeter】JSON Extractor变量包含转义字符,使用Beanshell脚本来消除
如果使用Jmeter的JSON Extractor提取的变量包含特殊字符,直接引用时会包含转义字符。可以使用Beanshell脚本来进行字符串转换,从而消除这些转义字符。 import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONArray; import com.ali…...
GO设计模式——5、建造者模式(创建型)
目录 建造者模式(Builder Pattern) 建造者模式的核心角色 优缺点 使用场景 注意事项 代码实现 建造者模式(Builder Pattern) 建造者模式(Builder Pattern)是将一个复杂对象的构建与它的表示分离&…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...
热门Chrome扩展程序存在明文传输风险,用户隐私安全受威胁
赛门铁克威胁猎手团队最新报告披露,数款拥有数百万活跃用户的Chrome扩展程序正在通过未加密的HTTP连接静默泄露用户敏感数据,严重威胁用户隐私安全。 知名扩展程序存在明文传输风险 尽管宣称提供安全浏览、数据分析或便捷界面等功能,但SEMR…...
