如何运行 c++ 代码/编译过程

运行cpp文件:

如何运行cpp文件:
方法1、vscode runcode
方法2、使用g++命令简单编译,在终端输入 g++ -o test test.cpp # -L. -l动态库名 (如果需要导入动态库)
方法3、对于复杂的程序,需要编写makefile or 使用cmake ,然后执行 make命令

CMake说明: 一般把CMakeLists.txt文件放在工程目录下,使用时,先创建一个叫build的文件夹(这个并非必须,因为cmake命令指向CMakeLists.txt所在的目录,例如cmake .. 表示CMakeLists.txt在当前目录的上一级目录。cmake后会生成很多编译的中间文件以及makefile文件,所以一般建议新建一个新的目录,专门用来编译),然后执行下列操作:

cd build
cmake ..
make
其中cmake .. 在build里生成Makefile,make根据生成makefile文件,编译程序,make应当在有Makefile的目录下,根据Makefile生成可执行文件。

C++编译过程主要分为,预处理、编译、汇编、链接四个过程。如下图所示:

在这里插入图片描述

第一步:预处理 将源代码的.c 、.cpp 、.h 等文件包含到一个文件中。在这个过程中会使用一些预处理指令要求编译器使用什么样的方式包含这些文件。预处理结束之后对于c语言编译器会生成一个.i 文件。C++会生成.ii文件。

预编译过程主要处理那些源代码中以#开始的预编译指令,主要处理规则如下:

·将所有的#define删除,并且展开所有的宏定义;

·处理所有条件编译指令,如#if,#ifdef等;

·处理#include预编译指令,将被包含的文件插入到该预编译指令的位置。该过程递归进行,及被包含的文件可能还包含其他文件。

·删除所有的注释//和 /**/;

·添加行号和文件标识,如#2 “hello.c” 2,以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号信息;

·保留所有的#pragma编译器指令,因为编译器须要使用它们;

第二步:编译 编译过程就是把预处理完的文件进行一系列词法分析,语法分析,语义分析及优化后生成相应的汇编代码文件.

第三步:汇编 汇编器是将汇编代码转变成机器可以执行的命令,每一个汇编语句几乎都对应一条机器指令。汇编相对于编译过程比较简单,根据汇编指令和机器指令的对照表一一翻译即可。

第四步:链接 链接器ld将各个目标文件组装在一起,解决符号依赖,库依赖关系,并生成可执行文件。

动态链接和静态链接

方法库大体上可以分为两类:静态库和动态库(共享库)。

1. windows中静态库是以 .lib 为后缀的文件,动态库是以 .dll 为后缀的文件。

2. linux中静态库是以 .a 为后缀的文件,动态库是以 .so为后缀的文件。

静态链接:

  • 静态库 在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。
  • 静态库可以简单看成是一组目标文件(.o .obj文件)的集合, 将若干个.o文件转换为静态库的过程,称之为打包. Linux下是使用ar工具, Windows下是使用lib.exe。
  • Linux下静态链接库的后缀是.libWindows下静态链接库的后缀是.a

动态链接:

  • 动态库在程序编译时并不会被连接到目标代码中,而是在程序运行时才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行是才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,增量更新。
  • 在Windows系统下的执行文件格式是PE(Portable Executable)格式,动态库需要一个DllMain函数做出初始化的入口,通常在导出函数的声明时需要有_declspec(dllexport)关键字。 跟exe有个main或者WinMain入口函数一样,DLL也有一个入口函数,就是DllMain。根据编写规范,Windows必须查找并执行DLL里的DllMain函数作为加载DLL的依据,它使得DLL得以保留在内存里。这个函数并不属于导出函数,而是DLL的内部函数。这意味着不能直接在应用工程中引用DllMain函数,DllMain是自动被调用的。
    对于动态链接库,DllMain是一个可选的入口函数。一个动态链接库不一定要有DllMain函数,比如仅仅包含资源信息的DLL是没有DllMain函数的。
  • Linux下gcc编译的执行文件默认是ELF格式,不需要初始化入口,亦不需要函数做特别的声明,编写比较方便。
    无需打包工具,直接使用编译器即可创建动态库。
  • Linux下动态链接库的后缀是.so;Windows下动态链接库的后缀是.dll

区别:

 当程序与静态库链接时,静态库中所包含的所有函数方法都会被copy到最终的可执行文件中去。这就会导致最终生成的可执行代码量相对变多,相当于编译器将代码补充完整了。这种方式会让程序运行起来相对快一些,不过也会有个缺点: 占用磁盘和内存空间,导致可执行exe程序过大。另外,静态库会被添加到和它链接的每个程序中去, 而且这些程序运行时, 都会被加载到内存中,无形中又多消耗了更多的内存空间。

与动态库链接的可执行文件只包含它需要的函数方法的引用表,而不是所有的函数代码,只有在程序执行时, 那些需要的函数代码才会被拷贝到内存中。这样就使可执行文件比较小, 节省磁盘空间,更进一步,操作系统使用虚拟内存,使得一份动态库驻留在内存中被多个程序使用,也同时节约了内存。不过由于运行时要去链接库会花费一定的时间,执行速度相对会慢一些。

       总的来说,静态库是牺牲了空间效率,换取了时间效率,动态库是牺牲了时间效率换取了空间效率,没有好与坏的区别,只看具体需要了。
       另外,一个程序编好后,有时需要做一些修改和优化,如果我们要修改的刚好是库函数的话,在接口不变的前提下,使用动态库的程序只需要将动态库重新编译就可以了,而使用静态库的程序则需要将静态库重新编译好后,将程序再重新编译一遍。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注