C--编译和链接见解

欢迎各位看官!如果您觉得这篇文章对您有帮助的话
欢迎您分享给更多人哦 感谢大家的点赞收藏评论

感谢各位看官的支持!!!请添加图片描述

一:翻译环境和运行环境

  在ANSIIC的任何一种实现中,存在两个不同的环境1,翻译环境:源代码 被转换成 可执行的机器指令(二进制指令) (电脑只能读懂这个)2,执行环境:实际执行代码其实翻译环境是由编译和链接两个⼤的过程组成的,⽽编译⼜可以分解成:预处理(有些书也叫预编
译)、编译、汇编三个过程

在这里插入图片描述

二.预处理(预编译),编译和汇编

2.1:预处理(预编译)

在预处理阶段。**源文件和头文件**都会被处理成后缀为(.i)的文件```c
命令:gcc -E test.c -o test.i **(-E到预处理结束,-o,生成test.i文件)**
> 1.预处理阶段主要处理那些源⽂件中#开始的预编译指令。
⽐如:#include,#define,处理的规则如下: 
> • 将所有的 #define 删除,并展开所有的宏定义。**(将#define定义的内容展开) 
> • 处理所有的条件编译指令,如: #if、#ifdef、#elif、#else、#endif 。
> • 处理#include 预编译指令,将包含的头⽂件的内容插⼊到该预编译指令的位置。
这个过程是递归进行的,也就是说被包含的头⽂件也可能包含其他⽂件。**
> • 删除所有的注释(变成空格) • 添加行号和文件名标识,方便后续编译器生成调试信息等。
>  • 或保留所有的#pragma的编译器指令,编译器后续会使用。

经过预处理后的 .i 文件中不再包含宏定义,因为宏已经被展开。并且包含的头文件呢都被插入到 .i文件中。所以当我们无法知道宏定义或者头文件是否包含正确的时候,可以查看预处理后的 .i 文件来确认。

2.2编译

词法分析,语法分析,语义分析。将C语言代码转换成汇编代码

gcc -S test.i -o test.s //生成test.s
例如: arr[index]=(index+4)*(2+6)

在这里插入图片描述

2.3 汇编

汇编器是将汇编代码转转变成机器可执行的指令(二进制),每⼀个汇编语句⼏乎都对应⼀条机器指令。就是根据汇编指令和机器指令的对照表⼀⼀的进⾏翻译,也不做指令优化。汇编的命令如下:

gcc -c test.s -o test.o
对test.c处理成test.o(二进制文件)

链接是⼀个复杂的过程,链接的时候需要把⼀堆⽂件链接在⼀起才⽣成可执行程序。
链接过程主要包括:地址和空间分配符号决议重定位等这些步骤。
链接解决的是⼀个项⽬中多⽂件、多模块之间互相调用的问题
在这里插入图片描述

三.运行环境

  1. 程序必须载入内存中。在有操作系统的环境中:⼀般这个由操作系统完成。在独立的环境中(单片机,里面无操作系统),程序的载入必须手工安排,也可能是通过可执行代码置入只读内存来完成。
    3. 程序的执行便开始。接着便调用main函数。
    4. 开始执⾏程序代码。这个时候程序将使⽤⼀个运⾏时堆栈(函数栈帧)(stack),存储函数的局部变量和返回地址程序是由一个个函数组成的,每创建一个函数就会创建一个运行时堆栈,运行时维护,结束时销毁)程序同时也可以使⽤静态(static)内存,存储于静态内存中的变量在程序的整个执行过程⼀直保留他们的值。
    5. 终止程序。正常终止main函数;也有可能是意外终止。
    在这里插入图片描述

四.预处理详解

1.1define 定义常量

__FILE__ //进⾏编译的源⽂件
__LINE__ //⽂件当前的⾏号
__DATE__ //⽂件被编译的⽇期
__TIME__ //⽂件被编译的时间
__STDC__ //如果编译器遵循ANSI C(C语言标准),其值为1,否则未定义//vs并未完全遵守

C语言设置的预定义符号,可以直接使用,预定义符号也是在预处理期间处理的
在这里插入图片描述

并且预处理后代码中**预定义符号**(你猜为什么叫预定义符号)就被替换了
printf("%s\n",C:\code\c-language-411\test_9_5\test_9_5\test.c)以下类推
63
Sep  5 2024
19:58:36
#include <stdio.h>
#define M 100
#define STR "hehe"
#define reg register
int main()
{int arr[M] = { 0 };     int a = M;printf("%d\n", M);  100 大家都是预处理的时候就已经换到printf("%d\n",100)这种了printf(STR);    hehereg int b= 10;//预处理后是register int b=10return 0;
}

1.2:关于define的一些规则

#define不要加;

#define M 100
if(a)
max=M;//这里的;让if else语句分开了本来是if(a)
else                                   max=M
max=0;                                else max=0;

但是有一种用法

#define CASE breakcase
int main()
{int a = 5;switch (a){case 1:CASE 2 :CASE 3 :CASE 4 :CASE 5 :CASE 6 :break;}return 0;
}

3.1define 定义宏 (宏里面的参数是整体替换的,并不会算出一个结果)

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

#define name(参数)替换的内容 (空格隔开)
#define ADD(n) ((n)*(n)) 这里的括号尽量不要省,不然容易错误
#define SQUARE(n) n+n
int main()
{int ret = 10 * SQUARE(5);     **结果是55不是100,变成了10*5+5**printf("%d", ret);return 0;

3.2 带有副作用的宏参数

当宏参数在宏的定义中出现超过⼀次的时候,如果参数带有副作⽤,那么你在使⽤这个宏的时候就可
能出现危险,导致不可预测的后果。副作⽤就是表达式求值的时候出现的永久性效果。

#define MAX(a,b) (a)>(b)?(a):(b)
int main()
{int a = 10;int b = 20;int ret = MAX(a++, b++);printf("ret=%d,b=%d", ret, b);21,22return 0;
}

在这里插入图片描述

4# 和##

4.1#(只能出现在宏体)

在这里插入图片描述

4.2##(记号粘合)

在这里插入图片描述

5.1#undef

#undef NAME (取消定义)

5.2 条件编译

调试性的代码,删除可惜,保留⼜碍事,所以我们可以选择性的编译。
在这里插入图片描述

6.头文件包含

(1):本地文件包含(一般这指自己创建的头文件的包含) #include “test.h”
> 查找策略:先在源文件所在目录下查找,如果该头⽂件未找到,编译器就像查找库函数头文件⼀样在标准位置查找头文件。
> (先在自己这个文件目录下找,找不到去库函数里面找)
> 如果找不到就提示编译错误。  
> Linux环境的标准头⽂件的路径:  /usr/include   
>  VS环境的标准头文件的路径: 
> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include 
> //这是VS2013的默认路径 注意按照⾃⼰的安装路径去找
(2):库文件包含 #include <stdio.h>

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

这样是不是可以说,对于库文件也可以使⽤ “” 的形式包含?

答案是肯定的,可以,但是这样做查找的效率就低些,当然这样也不容易区分是库文件还是本地文件了。

7.如何避免重复包含同一个头文件:

每次编译都要删除#include,然后用包含头文件的内容替换,头文件包含10次,替换10次,test.h文件的内容被包含在test(如果test.h文件比较大,这样预处理后代码量会剧增。如果工程比较大,有公共使用的头文件、被都能使用,又不做任何的处理,**那么后果真的不堪设想**。

如何解决头文件被重复引入的问题?
答案:条件编译。

每个头文件的开头写:

方法一:这种方法通过检查一个特定的宏是否已经被定义来决定是否包含头文件的内容.如果宏已经定义(意味着头文件已经被包含过一次),则跳过头文件的内容。

#ifndef __TEST_H__
#define __TEST_H__
#endif //__TEST_H__
这种方法通过检查一个特定的宏是否已经被定义来决定是否包含头文件的内容.
如果宏已经定义(意味着头文件已经被包含过一次),则跳过头文件的内容。

方法二:
#pragma once提供了另一种更简洁的方法来实现同样的功能。使用#pragma once,编译器在遇到这个指令时会确保当前头文件在同一个编译单元中只被包含一次,无论它是否被多次显式包含。

#pragma once

与宏定义保护相比,#pragma once的优点是:

  • 更简洁,不需要定义和检查宏。
  • 减少了命名冲突的风险,因为不需要为每个头文件创建一个唯一的宏名。
  • 在某些情况下,可以稍微提高编译速度,因为编译器可能能够更有效地优化包含关系

但是:需要注意的是,#pragma
once是非标准的,这意味着它的行为可能不是所有编译器都一致。但幸运的是,几乎所有现代主流编译器都支持这个指令,并且其行为也基本一致。因此,在大多数情况下,#pragma once是一个安全且方便的选择。

上述就是编译(包括预处理详解)和链接的全部内容了
能看到这里相信您一定对小编的文章有了一定的认可,有什么问题欢迎各位大佬指出
欢迎各位大佬评论区留言修正

您的支持就是我最大的动力请添加图片描述
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

BugReport中的App Processor wakeup字段意义

一、功耗字段意义&#xff1a; App processor wakeup:Netd基于xt_idletimer 待机下监视网络设备的收发工作状态&#xff0c;即当设备发生联网从休眠态变成为唤醒态时&#xff0c;会记录打醒者的uid(uid大于0)和网络类型(wifi或数据类型)、时间戳 实际日志&#xff1a;我们在B…

【Streamlit案例】制作销售数据可视化看板

目录 一、案例效果 二、数据分析 三、加载数据 四、网站前端 &#xff08;一&#xff09;网页标题和图标 &#xff08;二&#xff09;侧边栏和多选框 &#xff08;三&#xff09;主页面信息 ​&#xff08;四&#xff09;主页面图表 &#xff08;五&#xff09;隐藏部…

微信小程序操作蓝牙

主要流程&#xff1a; 1.初始化蓝牙适配器openBluetoothAdapter&#xff0c;如果不成功就onBluetoothAdapterStateChange监听蓝牙适配器状态变化事件 2.startBluetoothDevicesDiscovery开始搜寻附近的蓝牙外围设备 3.onBluetoothDeviceFound监听寻找到新设备的事件&#xff0c;…

用Python+flask+mysql等开发的Excel数据资产落地工具

话不多说 1)Excel文件上传,列表预览 2)选中要导入结构及数据的Excel文件 约束说明: 2.1)Excel文件的第一行约定为表头名称 2.2)系统自动识别字段列名及数据类型,目前不支持合并表头 3)Excel建表导入数据成功后,可在表源列表中预览查看 4)对数据表源可进行透视图设计管理,可对…

可以无限次使用o1-mini和o1-preview模型API接口的方法,并且比便宜便宜7倍以上

打开网站 https://open.xiaojingai.com 然后点击令牌页面&#xff0c;生成令牌&#xff0c;令牌就是api-key

Hive数仓操作(一)

Hive 介绍 Hive 是一个基于 Hadoop 的数据仓库工具&#xff0c;旨在简化大规模数据集的管理和分析。它将结构化数据文件映射为表&#xff0c;并提供类似 SQL 的查询功能。Hive 的数据存储在 Hadoop 分布式文件系统&#xff08;HDFS&#xff09;中&#xff0c;使用 Hive 查询语…

12.梯度下降法的具体解析——举足轻重的模型优化算法

引言 梯度下降法(Gradient Descent)是一种广泛应用于机器学习领域的基本优化算法&#xff0c;它通过迭代地调整模型参数&#xff0c;最小化损失函数以求得到模型最优解。 通过阅读本篇博客&#xff0c;你可以&#xff1a; 1.知晓梯度下降法的具体流程 2.掌握不同梯度下降法…

数据仓库简介(一)

数据仓库概述 1. 什么是数据仓库&#xff1f; 数据仓库&#xff08;Data Warehouse&#xff0c;简称 DW&#xff09;是由 Bill Inmon 于 1990 年提出的一种用于数据分析和挖掘的系统。它的主要目标是通过分析和挖掘数据&#xff0c;为不同层级的决策提供支持&#xff0c;构成…

云服务架构与华为云架构

目录 1.云服务架构是什么&#xff1f; 1.1 云服务模型 1.2 云部署模型 1.3 云服务架构的组件 1.4 云服务架构模式 1.5 关键设计考虑 1.6 优势 1.7 常见的云服务架构实践 2.华为云架构 2.1 华为云服务模型 2.2 华为云部署模型 2.3 华为云服务架构的核心组件 2.4 华…

【C++】STL标准模板库容器set

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:C ⚙️操作环境:Visual Studio 2022 目录 &#x1f4cc;关联式容器set(集合)简介 &#x1f4cc;set(集合)的使用 &#x1f38f;set(集合)的模板参数列表 &#x1f38f;set(集合)的构造函数 &#x1f38f;set(集合)的迭代…

翔云 OCR:发票识别与验真

在数字化时代&#xff0c;高效处理大量文档和数据成为企业和个人的迫切需求。翔云 OCR 作为一款强大的光学字符识别工具&#xff0c;在发票识别及验真方面表现出色&#xff0c;为我们带来了极大的便利。 一、翔云 OCR 简介 翔云 OCR 是一款基于先进的人工智能技术开发的文字识别…

搭建k8s集群服务(kubeadm方式)

准备工作 操作系统版本&#xff1a;CentOS Linux release 7.9.2009 (Core) 虚拟机硬件配置&#xff1a;2核8G内存&#xff08;最低2G&#xff09;&#xff0c;硬盘最低25G&#xff1b; linux内核版本&#xff08;3.10版本尝试失败&#xff09;&#xff1a;5.4.268-1.el7.elr…

基于Java+VUE+echarts大数据智能道路交通信息统计分析管理系统

大数据智能交通管理系统是一种基于Web的系统架构&#xff0c;通过浏览器/服务器&#xff08;B/S&#xff09;模式实现对城市交通数据的高效管理和智能化处理。该系统旨在通过集成各类交通数据&#xff0c;包括但不限于车辆信息、行驶记录、违章情况等&#xff0c;来提升城市管理…

【Python】AudioLazy:基于 Python 的数字信号处理库详解

AudioLazy 是一个用于 Python 的开源数字信号处理&#xff08;DSP&#xff09;库&#xff0c;设计目的是简化信号处理任务并提供更直观的操作方式。它不仅支持基础的滤波、频谱分析等功能&#xff0c;还包含了滤波器、信号生成、线性预测编码&#xff08;LPC&#xff09;等高级…

两个向量所在平面的法线,外积,叉积,行列式

偶尔在一个数学题里面看到求两向量所在平面的法线&#xff0c;常规方法可以通过法线与两向量垂直这一特点&#xff0c;列两个方程求解&#xff1b;另外一种方法可以通过求解两个向量的叉积&#xff0c;用矩阵行列式 (determinant) 的方式&#xff0c;之前还没见过&#xff0c;在…

【计算机网络】传输层UDP和TCP协议

目录 再谈端口号端口号范围划分认识知名端口号查看知名端口号两个问题 UDP协议UDP特点UDP的缓冲区基于UDP的应用层协议 TCP协议TCP协议格式确认应答机制超时重传机制连接管理机制&#xff08;三次握手与四次挥手&#xff09;理解TIME_WAIT状态理解CLOSE_WAIT状态滑动窗口快重传…

【C++】迭代器失效问题解析

✨ Blog’s 主页: 白乐天_ξ( ✿&#xff1e;◡❛) &#x1f308; 个人Motto&#xff1a;他强任他强&#xff0c;清风拂山冈&#xff01; &#x1f525; 所属专栏&#xff1a;C深入学习笔记 &#x1f4ab; 欢迎来到我的学习笔记&#xff01; 一、迭代器失效的概念 迭代器的作用…

【PyTorch】生成对抗网络

生成对抗网络是什么 概念 Generative Adversarial Nets&#xff0c;简称GAN GAN&#xff1a;生成对抗网络 —— 一种可以生成特定分布数据的模型 《Generative Adversarial Nets》 Ian J Goodfellow-2014 GAN网络结构 Recent Progress on Generative Adversarial Networks …

Python | Leetcode Python题解之第450题删除二叉搜索树中的节点

题目&#xff1a; 题解&#xff1a; class Solution:def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:cur, curParent root, Nonewhile cur and cur.val ! key:curParent curcur cur.left if cur.val > key else cur.rightif cur i…

解决Excel时出现“被保护单元格不支持此功能“的解决办法,详细喂饭级教程

今天有个朋友发过来一个excel文件&#xff0c;本来想修改表格的内容&#xff0c;但是提示&#xff0c;被保护单元格不支持此功能&#xff0c;对于这个问题&#xff0c;找到一个解决方法&#xff0c;现记录下来&#xff0c;分享给有需要的朋友。 表格文件名为aaa.xls,以WPS为例。…