c++ 开发生态环境、工作流程、生命周期-拾遗

拾遗 1  生态环境初识

当您使用Visual Studio 2019进行C++开发时,您将进入C++生态环境。以下是一些重要的概念和步骤:

  1. C++程序的结构: 一个典型的C++程序包括源文件(.cpp)、头文件(.h)、编译后的目标文件(.obj)和最终的可执行文件(.exe)或库文件(.lib、.dll)。

  2. 第三方库的工作方式: 如果您需要使用第三方库,通常会将其源代码或者预编译的库文件(.lib、.dll)包含到您的项目中。第三方库通常会包含头文件和库文件,您需要将这些文件包含到您的项目中,并在编译和链接过程中告诉编译器和链接器去哪里寻找这些文件。

  3. 相互引用和VS配置: 在Visual Studio中,您可以通过项目属性来配置第三方库的引用。具体步骤包括:

    • 将第三方库的头文件路径添加到项目的“包含目录”中,这样您的程序中就可以包含这些头文件。
    • 将第三方库的库文件路径添加到项目的“库目录”中,这样链接器就知道在哪里找到这些库文件。
    • 在“链接器->输入”中添加需要链接的库文件名,告诉链接器在链接时需要使用这些库文件。
  4. C++生态环境的其他方面:

    • C++标准库:C++提供了丰富的标准库,包括容器、算法、输入输出等功能。
    • C++编译器:Visual Studio 2019内置了Microsoft的C++编译器(MSVC),也可以选择其他编译器比如GCC或者Clang。
    • 调试工具:Visual Studio提供了强大的调试工具,可以帮助您调试C++程序。

总的来说,C++生态环境包括了C++编译器、标准库、第三方库、开发工具等,通过合理配置和使用这些工具,您可以进行高效的C++开发。

拾遗 2  从源码到目标码(obj)、可执行码(exe)、文件库(lib,dll)

        当进行C++开发时,源码经历了多个阶段才能最终转化为可执行文件或库文件。以下是这个过程的详细步骤:

  1. 预处理阶段: 在预处理阶段,C++编译器会处理源文件(.cpp)中的预处理指令,比如#include和#define。预处理器会将头文件内容替换到源文件中,并进行宏替换等操作,生成一个经过预处理的源文件(通常是一个临时文件)。

  2. 编译阶段: 经过预处理的源文件会被编译器翻译成汇编代码(.asm文件),这个过程包括词法分析、语法分析、语义分析和优化等步骤。编译器将源码翻译成目标代码,生成一个或多个目标文件(.obj文件),每个目标文件对应源文件中的一个编译单元。

  3. 链接阶段: 在链接阶段,链接器会将多个目标文件以及所需的库文件(静态库或动态库)链接在一起,生成最终的可执行文件(.exe)或者库文件(.lib、.dll)。链接器会解析符号引用,处理重定位等工作,确保最终的可执行文件或库文件可以正确运行。

        目标码(Object Code)是编译器生成的中间文件,包含了机器代码、符号表、重定位信息等。目标码是编译后的源码的中间表示,还不能被直接执行。目标码的作用是为了后续的链接阶段使用,链接器会将多个目标文件合并成最终的可执行文件或库文件。

        总的来说,C++程序从源码到目标码再到可执行文件或库文件经历了预处理、编译和链接三个阶段。目标码是编译器生成的中间文件,用于链接器生成最终的可执行文件或库文件。

拾遗3 一套具体的流程解释:

1. C/C++运行的四个步骤

        编写完成一个C/C++程序后,想要运行起来,必须要经过四个步骤:预处理、编译、汇编和链接。每个步骤都会生成对应的文件,如下图所示(注意后缀名):

 

2.名词解释

为了后面过程的介绍更方便,这里对C++编译过程中涉及的一些常用名词进行解释。

2.1 GCC、GNU、gcc与g++

    GNU:一个操作系统,具体内容不重要,感兴趣可以参考:

GCC、GNU到底啥意思?-CSDN博客文章浏览阅读1.9w次,点赞182次,收藏201次。本文目录GCC/GNU名字的由来GCCGNU理查德·斯托曼GPLLinux参考文献GCC/GNU名字的由来今天闲来无事,想要清理一下磁盘,遇到了一个名为 TDM-GCC-64 的文件夹,也就是gcc编译器所在的文件,突然好奇,编译器为什么叫GCC呢?于是Wiki了一下,然后便一发不可收拾……GCC原来GCC是——GNU编译器套装,那么问题来了,GNU又是啥?不知道你有没有好奇过:这..._gnuhttps://blog.csdn.net/qq_43617936/article/details/104504992

  • GCC:GNU Compiler Collection(GNU编译器集合)的缩写,可以理解为一组GNU操作系统中的编译器集合,可以用于编译C、C++、Java、Go、Fortan、Pascal、Objective-C等语言。
  • gcc:GCC(编译器集合)中的GNU C Compiler(C 编译器)
  • g++:GCC(编译器集合)中的GNU C++ Compiler(C++ 编译器)

简单来说,gcc调用了GCC中的C Compiler,而g++调用了GCC中的C++ Compiler。 - 对于 *.c 和 *.cpp 文件,gcc分别当作 c 和 cpp文件编译,而g++则统一当作cpp文件编译。

2.2 代码编译命令

gcc/g++常用指令选项:

2.3 GDB(gdb)

GDB(gdb)全称“GNU symbolic debugger”,是 Linux 下常用的程序调试器。 为了能够使用 gdb 调试,需要在代码编译的时候加上-g,如

g++ -g -o test test.cpp

本文中只演示从源代码生成可执行二进制文件的过程,暂不涉及调试过程。调试的配置会在另一篇文章中专门介绍。

3. C++编译过程详解

        初次使用Visual C++的时候一定有经历过项目的配置,肯定会对预编译头,链接器之类的东西心生疑惑,敲代码就敲代码,怎么有这么多要设置的东西。还有看着Windows版本的程序和Linux版本的编译完成后的文件夹也会疑惑,编译完除了程序怎么还有一堆.obj和.o文件。

        首先我们要明白一个流程,程序要运行起来,必须要经过四个步骤:预处理、编译、汇编和链接。每个步骤都会生成对应的文件。像下图一样,接下来我会分成四个步骤描述一下每个步骤都会做什么事

预编译:

        预编译如其名,就是编译前的一些准备工作。代码文件放到编译器面前,他肯定也不知道怎么去读,看到头文件他也不知道头文件里是什么,所以预编译就要把一些#define的东西完成文本替换,然后#include的文件里的内容复制到.cpp文件里,如果.h文件里还有.h文件,那递归展开,注释这些编辑器也不管的,完全是给程序员看的。简而言之,就是剔除掉编译器看不懂的东西,然后把所有头文件展开的一个过程。

编译:

        编译只是把我们写的代码转为汇编代码,它的工作是检查词法和语法规则,所以,如果程序没有词法或则语法错误,那么不管逻辑是怎样错误的,都不会报错。

汇编:

        汇编代码转换机器码,这个阶段,非底层的程序员不需要考虑, 编译器不会搞错的。也与c/c++开发者无关,但是我们可以利用反汇编来调试代码,学习汇编语言依然是必备的。

链接:

        配置链接库的重要性就体验在这里,配置的静态链接库还是动态链接库都会在这部分和最后的程序链接到一起。

        在这之前引用百度过来的一段话介绍下静态链接和动态链接的区别

    (1)静态链接是由链接器在链接时将库的内容加入到可执行程序中的做法。链接器是一个独立程序,将一个或多个库或目标文件(先前由编译器或汇编器生成)链接到一块生成可执行程序。静态链接是指把要调用的函数或者过程链接到可执行文件中,成为可执行文件的一部分。

  (2)动态链接所调用的函数代码并没有被拷贝到应用程序的可执行文件中去,而是仅仅在其中加入了所调用函数的描述信息(往往是一些重定位信息)。仅当应用程序被装入内存开始运行时,在Windows的管理下,才在应用程序与相应的DLL之间建立链接关系。当要执行所调用DLL中的函数时,根据链接产生的重定位信息,Windows才转去执行DLL中相应的函数代码。

        C语言代码经过编译以后,并没有生成最终的可执行文件(.exe 文件),而是生成了一种叫做目标文件(Object File)的中间文件(或者说临时文件)。目标文件也是二进制形式的,它和可执行文件的格式是一样的。对于 Visual C++,目标文件的后缀是.obj;对于 GCC,目标文件的后缀是.o。这就是一开始所说的编译完一堆.obj和.o文件的来源。

        目标文件经过链接(Link)以后才能变成可执行文件。既然目标文件和可执行文件的格式是一样的,为什么还要再链接一次呢,因为编译只是将我们自己写的代码变成了二进制形式,它还需要和系统组件(比如标准库、动态链接库等)结合起来,这些组件都是程序运行所必须的。链接(Link)其实就是一个“打包”的过程,它将所有二进制形式的目标文件和系统组件组合成一个可执行文件。完成链接的过程也需要一个特殊的软件,叫做链接器(Linker)。

        这里还要讲一个东西,C++程序编译的时候其实只识别.cpp文件。每个cpp文件都会分别编译一次,生成一个.o或者.obj文件。这个时候,链接器除了将目标文件和系统组件组合起来,还需要将编译器生成的多个.o或者.obj文件组合起来。

本节内容用下面的简单C++工程做演示。示例的文件结构如下:

|—— include|—— func.h
|—— src|—— func.cpp
|—— main.cpp

其中,main.cpp是主要代码,include/func.h是自定义函数的头文件,src/func.cpp是函数的具体实现

各个文件的内容如下:

// main.cpp
#include <iostream>
#include "func.h"using namespace std;int main(){int a = 1;int b = 2;cout << "a + b = " << sum(a, b) << endl;; return 0;
}
// func.h
#ifndef FUNC_H
#define FUNC_Hint sum(int a, int b);#endif
// func.cpp
#include "func.h"int sum(int a, int b) {return a + b;
}

3.1 预处理(Preprocess)

        预处理,顾名思义就是编译前的一些准备工作。

        预编译把一些#define的宏定义完成文本替换,然后将#include的文件里的内容复制到.cpp文件里,如果.h文件里还有.h文件,就递归展开。在预处理这一步,代码注释直接被忽略,不会进入到后续的处理中,所以注释在程序中不会执行。

        gcc/g++的预处理实质上是通过预处理器cpp(应该是c preprocess的缩写?)来完成的,所以我们既可以通过g++ -E,也可以通过cpp命令对main.cpp进行预处理:

g++ -E -I include/ main.cpp -o main.i
# 或者直接调用 cpp 命令
cpp -I include/ main.cpp -o main.i

        上述命令中: - g++ -E 是让编译器在预处理之后就退出,不进行后续编译过程,等价于cpp指令 - -I include/用于指定头文件目录 - main.cpp是要预处理的源文件 - -o main.i用于指定生成的文件名

        预处理之后的程序格式为 *.i,仍是文本文件,可以用任意文本编辑器打开。

执行完预处理后的文件结构如下:

|—— include|—— func.h
|—— src|—— func.cpp
|—— main.cpp
|—— main.i

 3.2 编译(Compile)

编译 只是把我们写的代码转为汇编代码它的工作是检查词法和语法规则,所以,如果程序没有词法或则语法错误,那么不管逻辑是怎样错误的,都不会报错
编译不是指程序从源文件到二进制程序的全部过程,而是指将经过预处理之后的程序转换成特定汇编代码(assembly code)的过程

编译的指令如下:

g++ -S -I include/ main.cpp -o main.s

与预处理类似,上述命令中: - g++ -S是让编译器在编译之后停止,不进行后续过程 - -I include/用于指定头文件目录 - main.cpp是要编译的源文件 - -o main.s用于指定生成的文件名

编译完成后,会生成程序的汇编代码main.s这也是文本文件,可以直接用任意文本编辑器查看。

执行完编译后的文件结构如下:

|—— include|—— func.h
|—— src|—— func.cpp
|—— main.cpp
|—— main.i
|—— main.s

3.3 汇编(Assemble)

汇编过程将上一步的 汇编代码( main.s) 转换成机器码(machine code), 这一步产生的文件叫做目标文件( main.o), 是二进制格式

gcc/g++的汇编过程通过 as 命令完成,所以我们可以通过g++ -cas命令完成汇编:

g++ -c -I include/ main.cpp -o main.o
# 或者直接调用 as 命令
as main.s -o main.o

上述指令中: - g++ -c让编译器在汇编之后退出,等价于 as - -I include/仍是用于指定头文件目录 - main.cpp是要汇编的源文件 - -o main.o用于指定生成的文件名

汇编这一步需要为每一个源文件(本文示例代码中为main.cppfunc.cpp)产生一个目标文件。因此func.cpp也需要执行一次这个汇编过程产生一个func.o文件:

# 可以用 g++ -c 命令一步生成 func.o
g++ -c -I include/ src/func.cpp -o src/func.o
# 当然也可以按照上面的预处理、编译、汇编三个步骤生成func.o

到了这一步,代码的文件结构如下:

|—— include|—— func.h
|—— src|—— func.cpp|—— func.o
|—— main.cpp
|—— main.i
|—— main.s
|—— main.o

 3.4 链接(Link)

C/C++代码经过汇编之后生成的目标文件(*.o)并不是最终的可执行二进制文件,而仍是一种中间文件(或称临时文件),目标文件仍然需要经过链接(Link)才能变成可执行文件

既然目标文件和可执行文件的格式是一样的(都是二进制格式),为什么还要再链接一次呢?
因为 编译只是将我们自己写的代码变成了二进制形式,它还需要和系统组件(比如标准库、动态链接库等)结合起来,这些组件都是程序运行所必须的
链接(Link)其实就是一个“打包”的过程,它将所有二进制形式的目标文件(.o)和系统组件组合成一个可执行文件。完成链接的过程也需要一个特殊的软件,叫做 链接器(Linker)
此外需要注意的是: C++程序编译的时候其实只识别.cpp文件,每个cpp文件都会分别编译一次,生成一个.o文件。这个时候,链接器除了将目标文件和系统组件组合起来,还需要将编译器生成的多个.o或者.obj文件组合起来生成最终的可执行文件(Executable file)

以本文中的代码为例,将func.omain.o链接成可执行文件main.out,指令如下:

g++ src/func.o main.o -o main.out
  • -o main.out用于指定生成的可执行二进制文件名
  • 由于g++自动链接了系统组件,所以我们只需要把自定义函数的目标文件与main.o链接即可。

运行main.out,结果如下:

./main.out
a + b = 3

3.5 小结

从上面的介绍可以看出,从C++源代码到最终的可执行文件的中间过程并不简单。了解预处理、编译、汇编、链接各个步骤的作用有助于我们处理更加复杂的项目工程。

不过也不必被这么麻烦的编译过程劝退,当我们编译简单.cpp代码时,

// hello.cpp
#include <iostream>
using namespace std;int main(){cout << "Hello, world!" << endl;return 0;
}

仍然可以直接使用g++命令生成可执行文件,而不必考虑中间过程:

g++ hello.cpp -o hello
./hello
Hello, world!

4. 参考教程

  1. GCC、GNU到底啥意思?
  2. C++ 预编译,编译,汇编,链接
  3. C/C++语言编译链接过程

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

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

相关文章

【算法实验】实验1

实验1-1 斐波那契数 【问题描述】斐波那契数 &#xff08;通常用 F(n) 表示&#xff09;形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始&#xff0c;后面的每一项数字都是前面两项数字的和。 定义&#xff1a;F(0) 0, F(1) 1, F(n) F(n-1) F(n-2) 其中n>1 要求计…

web前端算法简介之字典与哈希表

回顾 栈、队列 &#xff1a; 进、出 栈&#xff08;Stack&#xff09;&#xff1a; 栈的操作主要包括&#xff1a; 队列&#xff08;Queue&#xff09;&#xff1a; 队列的操作主要包括&#xff1a; 链表、数组 &#xff1a; 多个元素存储组成的 简述链表&#xff1a;数组&…

机器学习---xgboost算法

1. xgboost算法原理 XGBoost&#xff08;Extreme Gradient Boosting&#xff09;全名叫极端梯度提升树&#xff0c;XGBoost是集成学习方法的王 牌&#xff0c;在Kaggle数据挖掘比赛中&#xff0c;大部分获胜者用了XGBoost。 XGBoost在绝大多数的回归和分类 问题上表现的十分…

MYSQL的索引(一)

本章概览 索引的出现就是为了提高数据查询的效率&#xff0c;实际上可以提高读写效率的数据节后有很多 索引常见模型 哈希表是一种以键 - 值&#xff08;key-value&#xff09;存储数据的结构&#xff0c;用哈希函数把key计算成一个值&#xff0c;这个值代表一个位置&#xf…

使用docker搭建LNMP架构

目录 环境准备 下载安装包 服务器环境 任务分析 nginx部分 建立工作目录 编写 Dockerfile 脚本 准备 nginx.conf 配置文件 生成镜像 创建自定义网络 启动镜像容器 验证nginx MySQL部分 建立工作目录 编写 Dockerfile 准备 my.cnf 配置文件 生成镜像 启动镜像…

Puppeteer让你网页操作更简单(2)抓取数据

Puppeteer让你网页操作更简单(1)屏幕截图】 示例2 —— 让我们抓取一些数据 现在您已经了解了Headless Chrome和Puppeteer的工作原理基础知识,让我们看一个更复杂的示例,其中我们实际上可以抓取一些数据。 首先,请查看此处的Puppeteer API文档。如您所见,有大量不同的方法我…

Marin说PCB之传输线损耗---趋肤效应和导体损耗01

大家在做RF上的PCB走线或者是车载相机的上走线的时候经常会听那些硬件工程师们说你这个走线一定要保证50欧姆的阻抗匹配啊&#xff0c;还有就是记得加粗走做隔层参考。 有的公司的EE硬件同事会很贴心的把RF走线的注意事项给你备注在原理图上或者是layoutguide上&#xff0c;遇到…

php中常用的几个安全函数

1. mysql_real_escape_string() 这个函数对于在PHP中防止SQL注入攻击很有帮助&#xff0c;它对特殊的字符&#xff0c;像单引号和双引号&#xff0c;加上了“反斜杠”&#xff0c;确保用户的输入在用它去查询以前已经是安全的了。但你要注意你是在连接着数据库的情况下使用这个…

【Kafka-3.x-教程】-【二】Kafka-生产者-Producer

【Kafka-3.x-教程】专栏&#xff1a; 【Kafka-3.x-教程】-【一】Kafka 概述、Kafka 快速入门 【Kafka-3.x-教程】-【二】Kafka-生产者-Producer 【Kafka-3.x-教程】-【三】Kafka-Broker、Kafka-Kraft 【Kafka-3.x-教程】-【四】Kafka-消费者-Consumer 【Kafka-3.x-教程】-【五…

10.9.2 std::function 非OO的多态实现 Page185~187

源代码&#xff1a; #include <iostream> #include <functional> #include <list>using namespace std;//使用function模板类定义一个类型&#xff0c; //该类型要求作为T的 //函数类型是参数是string,返回值是void typedef std::function <void (std::s…

关于浏览器下载的时候出现失败,网络错误

我试过所有浏览器&#xff0c;谷歌&#xff0c;firefox,qq浏览器&#xff0c;还是edge都不好使&#xff0c; 1.看网上说是http debugger的问题&#xff0c;但是我没有找到这个服务项 2.也有说可以通过修改或设置下载路径解决 -------- 我通过下载一个叫xdm的软件&#xff…

CloudFlare平台下载的WARP一直连不上(warp无法连接)解决办法

遇到问题&#xff1a; 解决办法&#xff1a; 下载一个warp选ip的文件夹&#xff0c;选一下ip就行了。 下载链接如下&#xff1a; https://pan.kejicode.cn/d/Onedrive/WIN%E7%AB%AFwarp%E8%87%AA%E9%80%89IP(%E6%89%8B%E5%8A%A8%2B%E8%87%AA%E5%8A%A8).rar?signRqBdHIMyyhg…

代码随想录算法训练营第三十二天|122.买卖股票的最佳时机II、55. 跳跃游戏、45.跳跃游戏II

题目&#xff1a;122.买卖股票的最佳时机II 文章链接&#xff1a;代码随想录 视频链接&#xff1a;LeetCode:122.买卖股票的最佳时机|| 题目链接&#xff1a;力扣题目链接 图释&#xff1a; class Solution { public:int maxProfit(vector<int>& prices) {// 查看…

高效学习新编程语言的实践指南

学习一门新的编程语言或框架对于新手和有经验的程序员来说都是一个挑战。然而&#xff0c;通过采用一些有效的策略和方法&#xff0c;我们可以快速入门并掌握新的编程工具。本文将从新手和有编程经验两个不同的角度&#xff0c;分享一些实用的建议和技巧&#xff0c;帮助读者在…

Costco攻入山姆大本营

01 Costco深圳店开业火爆 “我今天不去Costco&#xff0c;早上还没开业&#xff0c;路上就已经堵车了&#xff0c;看来今天人很多&#xff0c;过几天再去”&#xff0c;原本计划在Costco开业当天去逛逛的张芸&#xff08;化名&#xff09;无奈只能放弃。 家住在Costco深圳店旁…

回归预测 | Python基于ISSA多策略改进麻雀优化ISSA-CNN-BiLSTM多输入单输出回归预测

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 原创改进&#xff0c; ISSA多策略改进麻雀优化ISSA-CNN-BiLSTM 多输入单输出回归 python代码 优化参数&#xff1a;filter,unints1,units2&#xff0c;学习率&#xff08;可添加&#xff09; 以下是三个主要的改进点&…

【Minio】常见问题解决思路

检查存储服务器对应的端口与应用服务器是否能够互通&#xff0c;通过ping|telnet命令检查、查看防火墙端口是否开放&#xff0c;检查防火墙端口linux系统和windows系统各有不同。检查电脑上的杀毒软件是否限制了网络端口和文件权限问题。检查minio配置信息是否正确&#xff0c;…

第三次面试总结 - 吉云集团 - 全栈开发

&#x1f9f8;欢迎来到dream_ready的博客&#xff0c;&#x1f4dc;相信您对专栏 “本人真实面经” 很感兴趣o (ˉ▽ˉ&#xff1b;) 专栏 —— 本人真实面经&#xff0c;更多真实面试经验&#xff0c;中大厂面试总结等您挖掘 目录 总结&#xff08;非详细&#xff09; 面试内…

【面试突击】并发编程、线程池面试实战

&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308; 欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术 的推送 发送 资料 可领取 深入理…

SpringBoot懒加载

什么是懒加载 懒加载是一种优化技术&#xff0c;它延迟加载或按需加载资源&#xff0c;以减少初始加载时间或提高性能。在不同的上下文中&#xff0c;懒加载有不同的应用和含义。在web开发中&#xff0c;懒加载通常指的是延迟加载图片数据。在长网页或应用中&#xff0c;如果图…