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

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是一个安全且方便的选择。

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

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

相关文章:

C--编译和链接见解

欢迎各位看官&#xff01;如果您觉得这篇文章对您有帮助的话 欢迎您分享给更多人哦 感谢大家的点赞收藏评论 感谢各位看官的支持&#xff01;&#xff01;&#xff01; 一&#xff1a;翻译环境和运行环境 在ANSIIC的任何一种实现中&#xff0c;存在两个不同的环境1&#xff0c;…...

【QT Quick】基础语法:基础类与控件

QML 的基础类和控件中&#xff0c;我们可以看到主要的几个分类&#xff1a;基础控件类、窗口类以及组件类。以下是对这些控件及其属性、继承关系等的详细讲解&#xff1a; 控件关系总结 QtObject 是所有 QML 对象的基类。它定义了基础属性&#xff0c;主要用于逻辑和数据封装…...

使用 SSH 连接 Docker 服务器:IntelliJ IDEA 高效配置与操作指南

使用 SSH 连接 Docker 服务器&#xff1a;IntelliJ IDEA 高效配置与操作指南 本文详细介绍了如何在 2375 端口未开放的情况下&#xff0c;通过 SSH 连接 Docker 服务器并在 Idea 中进行开发。通过修改用户权限、生成密钥对以及配置 SSH 访问&#xff0c;用户可以安全地远程操作…...

Gas费用是什么?

Gas费用是什么? 每5个Byte 需要1个GasGasLimit 用来限制合约最多执行多少次运算GasPrice 每次计算需要支付的费用在Web3的语境中,尤其是在以太坊(Ethereum)这样的区块链平台上,Gas费是一个核心概念。以下是关于Gas费的详细解释: 1. 定义 Gas是以太坊网络上的计算单位,…...

大语言模型(LLM)的子模块拆拆分进行联邦学习;大语言模型按照多头(Multi-Head)拆分进行联邦学习

目录 大语言模型(LLM)的子模块拆拆分进行联邦学习 方式概述 简单示例 大语言模型按照多头(Multi-Head)拆分进行联邦学习 场景设定 多头拆分与联邦学习 示例说明 大语言模型(LLM)的子模块拆拆分进行联邦学习 大语言模型(LLM)的子模块拆分进行联邦学习,主要涉及…...

Qt 概述

1. Qlabel HelloWorld 程序 使用纯代码实现 // widget.cpp Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);// 给当前这个lable对象&#xff0c;指定一个父对象QLabel* label new QLabel(this);// C语言风格的字符串可以直接…...

移动应用的界面配置-手机银行APP

设置登录界面为线性布局&#xff0c;组件垂直居中排列设置主页为滚动模式&#xff0c;包括布局、添加背景图片设置按钮样式&#xff0c;包括形状、边框线的宽度和颜色 设置登录界面 设置界面为线性布局&#xff0c;组件垂直居中排列 --android:gravity"center_vertical…...

微服务nginx解析部署使用全流程

目录 1、nginx介绍 1、简介 2、反向代理 3、负载均衡 2、安装nginx 1、下载nginx 2、解压nginx安装包 3、安装nginx​编辑 1、执行configure命令 2、执行make命令 4、启动nginx 1、查找nginx位置并启动 2、常用命令 3、反向代理 1、介绍反向代理配置 1、基础配置…...

华硕天选笔记本外接音箱没有声音

系列文章目录 文章目录 系列文章目录一.前言二.解决方法第一种方法第二种方法 一.前言 华硕天选笔记本外接音箱没有声音&#xff0c;在插上外接音箱时&#xff0c;系统会自动弹出下图窗口 二.解决方法 第一种方法 在我的电脑上选择 Headphone Speaker Out Headset 这三个选项…...

Unity中Socket_TCP异步连接,加入断线检测以及重连功能

1、服务端 using System; using System.Collections.Generic; using System.Text; #region 命名空间 using System.Net; using System.Net.Sockets; using System.Threading; using UnityEngine; #endregionnamespace AsynServerConsole {/// <summary>/// Tcp协议异步通…...

Android build子系统(01)Ninja构建系统解读

说明&#xff1a;本文将解读Ninja构建系统&#xff0c;这是当前Android Framework中广泛使用的构建工具。我们将从Ninja的起源和背景信息开始&#xff0c;逐步解读Ninja的优势和核心原理&#xff0c;并探讨其一般使用场景。然后介绍其在Android Framework中的应用及相关工具&am…...

徐老师的吉祥数

题目背景 文件读写 输入文件avoid.in 输出文件avoid.out 限制 1000ms 512MB 题目描述 众所周知&#xff0c; 3这个数字在有些时候不是很吉利&#xff0c;因为它谐音为 “散” 所以徐老师认为只要是 3的整数次幂的数字就不吉利 现在徐老师想知道&#xff0c;在某个范围[l,r] …...

使用html写一个能发起请求的登录界面

目录 head部分 内联样式部分 body部分 login-form类的div myModal类的div id script部分 总的代码 界面与操作演示 <!DOCTYPE html> <html lang"en"> <!DOCTYPE html> 这是文档类型声明&#xff0c;告诉浏览器这是一个 HTML文档。 <…...

五子棋双人对战项目(2)——登录模块

目录 一、数据库模块 1、创建数据库 2、使用MyBatis连接并操作数据库 编写后端数据库代码 二、约定前后端交互接口 三、后端代码编写 文件路径如下&#xff1a; UserAPI&#xff1a; UserMapper&#xff1a; 四、前端代码 登录页面 login.html&#xff1a; 注册页面…...

几种操作系统和几种cpu

常见的操作系统&#xff1a;windows&#xff0c;linux&#xff0c;macOS&#xff0c;统信&#xff0c;deepin&#xff0c;raspberry&#xff0c;andriod&#xff0c;iOS&#xff0c;鸿蒙&#xff0c;等等。 常见的cpu&#xff1a;intel&#xff0c;amd&#xff0c;龙芯&#x…...

[Cocoa]_[初级]_[使用NSNotificationCenter作为目标观察者实现时需要注意的事项]

场景 在开发Cocoa程序时&#xff0c;由于界面是用Objective-C写的。无法使用C的目标观察者[1]类。如果是使用第二种方案2[2],那么也需要增加一个代理类。那么有没有更省事的办法&#xff1f; 说明 开发界面的时候&#xff0c;经常是需要在子界面里传递数据给主界面&#xff0…...

彩虹易支付最新版源码及安装教程(修复BUG+新增加订单投诉功能)

该源码当前版本为较新的版本&#xff0c;新增了订单投诉功能和一套精美的二次元模板。 此版本为全开源版本&#xff0c;所有文件均未加密。系统默认安装完成后无法直接打开&#xff0c;需要进一步配置。 本站特别针对BUG文件进行了修复&#xff0c;且在PHP7.4环境下表现良好。…...

ping香港服务器超时的原因通常有哪些?

Ping命令用于测试计算机与目标服务器之间的网络连接。当您在尝试使用ping命令检测服务器时遇到超时的情况&#xff0c;通常可能是由以下原因造成的&#xff1a; 1. 网络连接问题&#xff1a; - 本地网络故障&#xff1a;如网线损坏、路由器故障或配置不当。 - ISP(互联网服务提…...

书生大模型实战(从入门到进阶)L3-彩蛋岛-InternLM 1.8B 模型 Android 端侧部署实践

目录 1 环境准备 1.1 安装rust 1.2 安装Android Studio 1.3 设置环境变量 2 转换模型 2.1 安装mlc-llm 2.2 (可选)转换参数 2.3 (可选)生成配置 2.4 (可选)上传到huggingface 2.5 (可选) 测试转换的模型 3 打包运行 3.1 修改配置文件 3.2 运行打包命令 3.3 创建签…...

setState是同步更新还是异步更新

setState是同步更新还是异步更新 先说结论setState为什么设计为异步react18之前为什么不确定是同步还是异步呢react18之后setState有哪些改动 先说结论 React18之前&#xff1a;使用了ReactDOM.render&#xff0c;setState在React调度流程中是异步更新&#xff0c;在原生事件和…...

设计模式和设计原则回顾

设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...