笔记24-1(C语言进阶 程序环境和预处理)

2023-11-04

目录

 注:

推荐书籍

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

编译和链接

翻译环境

编译

预处理

编译

汇编

链接

运行环境/执行环境


 注:

        本笔记参考:B站up 鹏哥C语言

推荐书籍

  • 《程序员的自我修养》

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

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

  1. 翻译环境:在这个环境中源代码被转换成可执行的机器指令。
  2. 执行环境:这个环境被用于实际执行代码。

编译和链接

翻译环境

  • 每一个源文件都会 单独 经过编译器的处理,各自写成形成一个目标文件(.obj)。
  • 这些目标文件会一起经过链接器,连接器会把这些 目标文件 还有一些 链接库 全部链接在一起,生成一个可执行程序。

链接库(Libraries)

以fread函数的链接库为例

LIBC.LIB Single thread static library, retail version
LIBCMT.LIB Multithread static library, retail version
MSVCRT.LIB Import library for MSVCRT.DLL, retail version

这些链接库内包含的是fread函数的一些相关信息。

翻译环境包含了两大步骤:

  1. 编译 - 把每个源文件进行编辑处理,形成目标文件,编译依赖的是 编译器 。(VS 作为一种IDE,本身自带了编译器,一般是 cl.exe )
  2. 链接 - 依赖的是 链接器 。(VS 同样有链接器,一般是 link.exe )

在Linux系统下的编译过程展示(test.c):

gcc test.c — 默认生成一个 a.out(可执行程序),这个可执行程序(a.out)可以通过输入 .\a.out 的方式执行它。

编译

预处理

接下来首先解析预处理步骤,在预处理阶段,编译器完成的工作有:

  • 头文件的包含;
  • 对#include定义的符号和宏的替换;
  • 注释的删除。

例如:

#include<stdio.h>

int g_val = 2022;
int ADD(int x, int y)
{
    return x + y;
}
int main()
{
    int a = 10;
    int b = 20;
    int ret = ADD(a, b);
    printf("%d\n", ret);

    return 0;
}

接下来,在Linux系统下编译该代码。

第一步(只执行预处理步骤):

gcc test.c - E            //直接在控制台上进行输出
gcc test.c -E > test.i    //把输出结果重定向到test.i中

此时如果打开 test.i ,会发现,文件内部存在大量之前没有见过的内容,截取一部分:

注:在写程序引用头文件时,需要使用 include ,如 #include<stdio.h> 这种代码的工作原理就是把 stdio.h 里面的代码拷贝到 源文件 里面。

会发现

  • flockfile
  • ftrylockfile
  • funlockfile

这三个符号,那如何证明这三个符号也出现在 stdio.h 这个头文件下面呢?现在让我们打开头文件所在目录:/usr/include/

发现该目录下面存在大量头文件。接下来打开 stdio.h ,vim stdio.h

同样,在 stdio.h 中,我们找到了这三个字符。这就可以证明源文件在引用头文件时,会拷贝头文件的内容。

 通过上面的例子我们可以发现,在预处理阶段,完成了头文件的包含


接下来再在源代码 test.c 中增加 宏 和 定义:

再次编译:gcc test.c -E > test.i

再次打开 test.i ,观察:

发现

  1. include指令已经不见了;
  2. 原本的 M 已经变成了 1000 了;
  3. define定义的 也替换成了 ((100)>(200)?(100):(200)) 。

所以预处理阶段完成的第二件事情就是对#define定义的符号和宏的替换


而如果再在 test.c 中写入注释:

再次编译至预处理步骤,会发现

原本注释所在的地方,注释不见了。所以预处理阶段完成的第三件事情就是删除注释

编译

在编译阶段,完成的工作有:

  • 语法分析
  • 词法分析
  • 语义分析
  • 符号汇总

也就是把C语言代码转换成汇编代码。(涉及 编译原理)

在Linux系统下,编译 test.c 对应的命令是

gcc -S test.c            //编译 test.i 也可以
gcc -S test.c > test.s

(接下来的说明使用的例子也是 test.c

在执行完编译后,写入 test.s 内的是汇编代码:

汇编

在Linux系统下对 test.c 进行汇编的命令是

gcc -c test.c
gcc -c test.c > test.o    //(在Windows平台下是 test.obj )

生成的是目标文件 test.o

打开文件

发现出现的是无法看懂的乱码,其实这些乱码就是二进制信息。

从上面可以得出,在汇编中进行的工作是:

  • 把汇编代码转换成机器指令(二进制指令);
  • 另外,在汇编中还完成了 生成符号表。

注意:test.o 这个文件是有格式的,这个格式就是 elf格式 。在这种格式下, test.o 被划分成了一个一个的“段”,每个段内存放的内容是不同的。(注:可执行文件 .out 也是elf格式的)

既然有格式,那么理所当然就可以使用工具看懂这个文件,比如:readelf 。接下来就使用 readelf 打开 test.o 。

使用命令:

readelf test.o -s

生成了:

其中,红框内的符号可以和 test.c 内的全局变量、ADD函数、主函数和printf函数对应起来。

注意:编译阶段,符号汇总也是对上述这些变量和函数进行的汇总。

为了更好地说明编译器进行工作的过程,我们把 主函数 和 ADD函数 拆成两部分(使用VS 2022)。

接下来在Linux内进行预处理:

gcc test.c -c 生成 test.o

gcc add.c -c 生成 add.o

接下来查看 add.o

在这里可以看到 ADD 对应的值是 1 。

再观察 test.o

这就是编译阶段进行的符号汇总,之后在汇编阶段生成的符号表

 那么生成的符号表有什么用吗?这就要进入下一个阶段 —— 链接 了。

链接

链接 — 把多个目标文件和链接库进行链接

在该阶段完成的任务是:

  • 合并段表;(将不同目标文件elf格式下的相同段合并起来)

  • 符号表的合并和符号表的重定位。

假如删除拥有有效地址的ADD,最后生成的表就会是这样:

ADD拥有的就是无效的地址,这时候如果继续编译,会发现无法通过。

这个报错就是因为ADD没有意义导致的。

注:只有当地址有效时,链接器才可以通过地址找到函数。

所以编译阶段的符号汇总汇编阶段的生成符号表链接阶段的合并符号表和重定位都是在为链接时跨文件链接做准备。

运行环境/执行环境

程序运行的过程:

  1. 程序必须载入内存中。这个操作如果是在有操作系统的环境中,一般是由操作系统完成;如果是在独立的系统中,则需要手工进行安排,或者通过可执行代码置入只读内存的方式完成。
  2. 程序的执行就是开始,接着就是调用main函数。
  3. 开始执行程序代码。这个时候程序将运行时堆栈(stack)(或者函数栈帧),存储函数的局部变量和返回地址。同时,程序也可以使用静态(static)内存,存储在静态内存中的变量在程序的整个执行过程中会一直保留他们的值。
  4. 终止程序。正常终止于main函数,也可能是以外终止。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

笔记24-1(C语言进阶 程序环境和预处理) 的相关文章

随机推荐

  • Elasticsearch 开启https鉴权

    Elasticsearch 早期的版本配置鉴权 由于插件收费 所以配置起来比较麻烦 但是最近发现Elasticsearch的8 2版本中可以配置https及鉴权的操作 所以记录一下给想要获取该知识的人 分享一下 第一步 修改elastics
  • Android开发屏幕适配方案

    由于Android系统的开放性 任何用户 开发者 硬件厂商和运营商都可以对Android系统和硬件进行定制 修改成他们自己所需要的样子 使得随着Android设备的增多 设备碎片化 系统碎片化 屏幕尺寸碎片化和屏幕碎片化的程度也在不断加深
  • 竞赛知识点4【搜索】

    文章目录 复习 栈和队列的概念 树 1 1 深度优先搜索 dfs 1 1 1 概念 1 1 2 例题 1 输出n个数的全排列 2 输出n个数中选m个的组合 3 N皇后 8皇后的升级版 4 马踏棋盘 1 1 3 DFS大体框架 1 1 4 剪
  • Springboot-MDC+logback实现日志追踪

    一 MDC介绍 MDC Mapped Diagnostic Contexts 映射诊断上下文 该特征是logback提供的一种方便在多线程条件下的记录日志的功能 某些应用程序采用多线程的方式来处理多个用户的请求 在一个用户的使用过程中 可能
  • Linux 安装cento

    在虚拟机中安装CentOS7 http www centoscn com image text setup 2014 0723 3341 html CentOS 7 下 ifconfig command not found 解决办法 htt
  • localStorage.setItem()使用

    localStorage setItem 使用
  • python自测100题

    如果你在寻找python工作 那你的面试可能会涉及Python相关的问题 通过对网络资料的收集整理 本文列出了100道python的面试题以及答案 你可以根据需求阅读测试 python基础 Q1 什么是Python Python是一种面向对
  • Scala学习第一天(十三):映射(可变/不可变Map;Map基本操作)

    学习目标 映射 不可变Map 可变Map Map基本操作 映射 Map可以称之为映射 它是由键值对组成的集合 在Scala中 Map也分为 不可变Map 可变Map 不可变Map 语法 val var map Map 键 gt 值 键 gt
  • Spring @ComponentScan 自定义扫描规则

    Spring ComponentScan 组件中扫描规则使用场景 package org example cap2 config import org springframework context annotation Bean impo
  • Apache Beam简介及相关概念

    文章目录 一 简介 二 基本概念 1 Pipelines 2 PCollection 3 Transforms 4 ParDo 5 Pipeline I O 6 Aggregation 7 User defined functions UD
  • H5 手机键盘兼容

    文章目录 键盘弹起页面表现 ios表现 安卓表现 监听软键盘弹起和收起 ios监听focus blur事件 安卓还可见监听页面高度 获取软键盘高度 通过window visualViewport异步获取 唤起软键盘始终让焦点元素滚动到可视区
  • SQL执行计划的十大参数

    调用分析指令分析sql再进行对应的调优 explaion select 十个参数 id 编号 select type 查询类型 table 表 type 索引类型 possible keys 预测可能用到的索引 key 实际使用的索引 ke
  • css实现垂直居中6,CSS实现水平、垂直居中的6种方式

    1 块级元素和行内元素 2 水平居中和垂直居中 3行内元素的水平居中 1 table 2 设置line height 3 text align center 4 margin 0 auto 5 绝对定位 6 flex弹性盒模型 7 calc
  • Http协议、get和post请求整理

    1 什么是GET 和 POST GET 和 POST 其实都是 HTTP 的请求方法 除了这 2 个请求方法之外 HTTP 还有 HEAD PUT DELETE TRACE CONNECT OPTIONS 这 6 个请求方法 所以HTTP的
  • VMware16 Pro的安装及VMware配置CentOS7虚拟机(快照使用)

    VMware16 Pro下载安装 1 进入官网下载 VMware官网 2 选择资源栏目 点击产品下载 3 找到VMware Workstation Pro进行下载 搜索框搜索 vmware workstation 16 pro for wi
  • mysql中双引号和单引号有什么区别

    mysql中双引号和单引号有什么区别 前2天看到有人问 mysql中双引号和单引号有什么区别 希望大家可以关注下公众号 支持一下 鞠躬感谢 我就直接po代码和截图了 如下 select from employees where last n
  • vue3 + vite npm 组件库开发(一)

    1 创建项目 创建一个普通的vite vue3 项目即可 我这里创建的是ts的项目 js也可 根据自己的使用习惯 2 配置项目 根目录下创建packages目录作为组件的开发包 目录下index ts 作为整个组件库的出口文件 导出组件 i
  • “目标检测“+“视觉理解“实现对输入图像的理解

    提出了GLIPv2 一种基于VL的理解模型 它服务于localization任务 例如 目标检测 实例分割 和视觉语言 VL 理解任务 例如 VQA 图像字幕 论文地址 https arxiv org pdf 2206 05836 pdf
  • 如何利用ProcessOn 做资产管理流程图

    资产管理 是一家公司最重要的管理活动 好的资产管理可以让资源最优化利用 实现资产价值的最大化 可以帮助组织管理和降低风险 同时当需要决策的时候 对资产数据进行分析和评估 也可以帮助做出更明智的决策 如优化资产配置 更新技术设备等 一 资产流
  • 笔记24-1(C语言进阶 程序环境和预处理)

    目录 注 推荐书籍 程序的翻译环境和执行环境 编译和链接 翻译环境 编译 预处理 编译 汇编 链接 运行环境 执行环境 注 本笔记参考 B站up 鹏哥C语言 推荐书籍 程序员的自我修养 程序的翻译环境和执行环境 在ANSI C的任何一种实现