C--编译和链接见解

news2024/10/3 22:28:57

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

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

一:翻译环境和运行环境

  在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);    hehe
	reg int b= 10;//预处理后是register int b=10
	return 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,22
	return 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.coloradmin.cn/o/2186963.html

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

相关文章

动手学深度学习(李沐)PyTorch 第 7 章 现代卷积神经网络

7.1 深度卷积神经网络&#xff08;AlexNet&#xff09; 在计算机视觉中&#xff0c;直接将神经网络与其他机器学习方法进行比较也许不公平。这是因为&#xff0c;卷积神经网络的输入是由原始像素值或是经过简单预处理&#xff08;例如居中、缩放&#xff09;的像素值组成的。但…

【C++】——list的介绍和模拟实现

P. S.&#xff1a;以下代码均在VS2019环境下测试&#xff0c;不代表所有编译器均可通过。 P. S.&#xff1a;测试代码均未展示头文件stdio.h的声明&#xff0c;使用时请自行添加。 博主主页&#xff1a;Yan. yan.                        …

亚马逊云乱扣费,被不知不觉扣钱真的好气呀

之前申请了亚马逊云12个月免费&#xff0c;一直也没用&#xff0c;也没登录&#xff0c;今天突然看到银行扣费信息&#xff0c;扣了我21美元&#xff0c;已经扣了我几个月了&#xff0c;登录亚马逊后台&#xff0c;实例为0的情况下&#xff0c;每个月都能扣21美元&#xff0c;国…

【HTML+CSS】留言板plus实现全过程

创建一个具有动态留言的简约风格留言板 在本教程中&#xff0c;我们将学习如何创建一个简约风格的留言板&#xff0c;它具备动态留言显示和一些基本动画效果。这个留言板将使用HTML和CSS构建&#xff0c;最终实现一个既美观又实用的界面。 准备工作 首先&#xff0c;确保你的…

UNRAID使用rclone挂在alist网盘

UNRAID使用rclone挂在alist网盘 需求&#xff1a;考虑异地备份&#xff0c;将部分重要的资料上传至网盘&#xff0c;保证nas中的资料安全。 考虑&#xff1a;当然网盘备份存在安全性问题&#xff0c;后续也可以通过加密的方式进行上传&#xff0c;不过这是后话&#xff0c;有精…

Python常见问题解答:从基础到进阶

Python常见问题解答&#xff1a;从基础到进阶 Python 是一种简单易学、功能强大的编程语言&#xff0c;广泛应用于数据分析、Web 开发、自动化脚本、人工智能等领域。即便如此&#xff0c;Python 开发者在编写代码的过程中&#xff0c;常常会遇到各种各样的问题。本文将从基础…

java集合 -- 面试

Java集合框架体系 ArrayList底层实现是数组 LinkedList底层实现是双向链表 HashMap的底层实现使用了众多数据结构&#xff0c;包含了数组、链表、散列表、红黑树等 List ps : 数据结构 -- 数组 ArrayList源码分析 ArrayList底层的实现原理是什么? ArrayList list new…

HKMG工艺为什么要用金属栅极?

知识星球里的学员问&#xff1a;在HKMG工艺中&#xff0c;会用到HfO2等作为栅介质层&#xff0c;为什么不能再用多晶硅做栅极&#xff0c;而是改为金属栅极&#xff1f; 什么是HKMG工艺&#xff1f; HKMG&#xff08;High-K Metal Gate &#xff09;&#xff0c;是45nm&#…

《深度学习》OpenCV 背景建模 原理及案例解析

目录 一、背景建模 1、什么是背景建模 2、背景建模的方法 1&#xff09;帧差法(backgroundSubtractor) 2&#xff09;基于K近邻的背景/前景分割算法BackgroundSubtractorKNN 3&#xff09;基于高斯混合的背景/前景分割算法BackgroundSubtractorMOG2 3、步骤 1&#xff09;初…

利士策分享,年前如何合理规划,轻松搞点小钱?

利士策分享&#xff0c;年前如何合理规划&#xff0c;轻松搞点小钱&#xff1f; 随着春节的日益临近&#xff0c;不少人开始为过年期间的开销而犯愁。 如何在年前合理规划&#xff0c;轻松搞点小钱&#xff0c;成了大家热议的话题。 别担心&#xff0c;这里有几个既实用又不伤…

华为OD机试 - 分班问题(Java 2024 E卷 200分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;E卷D卷A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加…

华为OD机试 - 密室逃生游戏(Python/JS/C/C++ 2024 E卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

杀疯啦-yolov11+deepsort的目标跟踪实现

目录 yolov11介绍——实时端到端物体检测 概述 主要特征 支持的任务和模式 性能指标 总结 deepsort介绍&#xff1a; yolov11结合deepsort实现目标跟踪 效果展示 训练与预测 UI设计 其他功能展示 完整代码实现UI界面 yolov11介绍——实时端到端物体检测 概述 YOLO…

IDEA 使用技巧与插件推荐

目录 前言1. IDEA 使用技巧1.1 快捷键优化与应用1.2 高效调试与日志分析1.3 代码模板与片段的自定义 2. 插件推荐2.1 MyBatisX2.2 Lombok2.3 CheckStyle-IDEA2.4 Key Promoter X2.5 GitToolBox2.6 Rainbow Brackets 3. IDEA 性能优化3.1 内存与堆栈设置3.2 禁用不必要的插件3.3…

论文翻译 | Language Models are Few-Shot Learners 语言模型是少样本学习者(中)

3 结果 在图3.1中&#xff0c;我们展示了第2节描述的8个模型的训练曲线。对于这个图表&#xff0c;我们还包括了6个额外的超小型模型&#xff0c;参数数量少至100,000。正如[KMH20]中观察到的&#xff0c;当有效利用训练计算时&#xff0c;语言建模性能遵循幂律。在将这个趋势再…

FreeRTOS篇15:中断管理

一.中断优先级 任何中断的优先级都大于任务&#xff01; 在我们的操作系统&#xff0c;中断同样是具有优先级的&#xff0c;并且我们也可以设置它的优先级&#xff0c;但是他的优先 级并不是从 015 &#xff0c;默认情况下它是从 515 &#xff0c;0~4 这 5 个中断优先级不是 F…

【逐行注释】PF(Particle filter,粒子滤波)的MATLAB代码(附源代码)

文章目录 程序设计1. 介绍2. 系统模型3. 算法步骤 源代码运行结果 程序设计 1. 介绍 粒子滤波是一种用于动态系统状态估计的先进方法&#xff0c;广泛应用于机器人定位、目标跟踪和金融预测等领域。该算法通过一组粒子及其权重来表示系统状态的概率分布&#xff0c;能够有效处…

JavaSE——面向对象8:Object类详解(==与equals的区别、hashCode、toString方法)

目录 一、与equals()的区别 (一)是一个比较运算符 (二)equals是Object类中的方法&#xff0c;只能判断引用类型 (三)equals方法重写练习 1.练习1 2.练习2 3.练习3 二、hashCode方法 三、toString方法 1.默认返回&#xff1a;全类名(包名类名)哈希值的十六进制 (1)不…

VS编译器实用调试技巧

一.什么是bug bug本意是"昆虫"或"虫子&#xff3d;&#xff0c;现在一般是指在电脑系统或程序中&#xff0c;隐藏着的一些未被发现的缺陷或问题&#xff0c;简称程序漏洞。“Bug"的创始人格蕾丝&#xff0e;赫柏&#xff08;Grace Murray Hopper)&#xff…

算法笔记(七)——哈希表

文章目录 两数之和判定是否互为字符重排存在重复元素存在重复元素 II字母异位词分组 哈希表&#xff1a;一种存储数据的容器&#xff1b; 可以快速查找某个元素&#xff0c;时间复杂度O(1)&#xff1b; 当频繁查找某一个数时&#xff0c;我们可以使用哈希表 创建一个容器&#…