C++生成二级制文件过程(预处理->编译->链接 )

转载请注明出处

Windows下C++编程,通过VC生成工程,编写C++源文件,点运行,代码没问题直接出结果。VC什么都帮我们搞了,不了解其中过程也完全没问题。

转到linux下写c++,总觉得有点虚,毕竟很多时候需要自己去构建。网上找了一些相关的文章,大多讲得高深,弄懂其过程后来写一篇不高深但易懂的,方便回忆。有不准确的地方欢迎指正。

C++包括源文件(.cpp)和头文件(.h),头文件包含变量的声明和类定义,源文件包含变量的定义。当然你也可以只用源文件来组织程序,但使用.h文件可以使程序结构更清晰。

linux下,c++生成二进制文件通常使用1条命令即可

  g++ source1.cpp source2.cpp source3.cpp -o main

其实这过程包含预处理、编译和链接3个过程,预处理包含宏定义、包含指令和条件编译指令。

宏定义是简单的替换,将某个变量值替换为另一个内容,之前学C的时候把它当全局变量使用(#define PI 3.14),包含指令可以包含其他C++文件,一般包含.h文件,预处理后可以将包含的.h文件内容展开(.h文件中包含的文件也被展开)。条件编译利用宏定义和包含指令,对代码展开内容做控制。比如:main.cpp中include "student.h"、include "teacher.h",student.h文件中又include "teacher.h",那么teacher.h被include了2次,Teacher类重复定义,编译会报错。在Teacher.h中可以使用条件编译(#ifndef _TEACHER_H #define _TEACHER_H ... #endif),保证Teacher定义只有一次。

编译过程将每个编译单元的代码翻译为机器码,每个编译单元产生一个目标文件(包含未解决符号表、导出符号表、地址重定向表和机器码)。变量、函数分为外链接(extern,符号导出)和内链接(static,符号不导出)

static和extern

  static:在example.h文件中全局范围内定义的变量x,变量a只可以在本编译单元内使用,不对外暴露该变量(链接时不会令其他编译单元拿到该变量)。所以,a.cpp文件(a编译单元)只要include "example.h",就可以在本编译单元使用变量x。b.cpp(b编译单元)也include "example.h",也可以在它的编译单元内使用变量x。使用的是各自版本的x,链接时彼此不冲突。

  extern:全局变量的声明,变量可以声明多次,不会报错。extern int x,本编译单元会操作一个变量x,但x的定义并不在此编译单元。所以编译时发现访问没有定义的变量x不会报错,在链接时会找到它的定义,多个编译单元共享一个全局变量。

所以,在.h文件中全局变量的定义,要么是static的,各编译单元用各自的。要么是extern的声明,我要用到一个全局变量,如果没找到定义就在别的编译单元内找找。如果在.h文件中定义一个变量,不合理。.h文件可能会被多个编译单元include,那链接时必然出现变量重定义。

链接过程将多个目标文件链接(依赖目标文件的3个表),组成完整二进制程序。此时可能的错误有:extern的变量却没有找到定义在哪;某个变量被多次定义。

以上就是C++源文件到可执行程序的处理过程,细节比这描述要复杂得多,但还是要先有骨再有肉。欢迎一起讨论。

时间: 2024-10-02 06:28:50

C++生成二级制文件过程(预处理->编译->链接 )的相关文章

GCC编程四个过程:预处理-编译-汇编-链接

在Linux下进行C语言编程,必然要采用GNU GCC来编译C源代码生成可执行程序. 一.GCC快速入门Gcc指令的一般格式为:Gcc [选项] 要编译的文件 [选项] [目标文件]其中,目标文件可缺省,Gcc默认生成可执行的文件名为:编译文件.out我们来看一下经典入门程序"Hello World!"# vi hello.c #include <stdlib.h>#include <stdio.h>void main(void){printf("he

一个简单的groovy script生成的class文件及其反编译

Groovy def task = { println "Hello from source code-Task" } task() def task2 = { println "Hello from source code-Task2" } class B { String getName(){ return "Young" } } println new B().getName(); task2(); 结果 Hello from source

[转]keil编译链接过程以及ARMCC、ARMASM、FROMELF、ARMLINK、ARMAR的使用

1.keil5 MDK的编译工具 armar.exe armasm.exe armcc.exe armlink.exe fromelf.exe 以及动态链接库 armcompiler_libFNP.dll 2.各工具用法 >>>armar.exe 可以在windows下使用命令行切换到该程序所在文件夹(keil5\ARM\ARMCC\bin),执行armar.exe -h进行命令查看.若有gitbash的话直接在该文件夹下右键选择gitbash here,之后运行./armar.exe

Linux下C语言执行过程(预处理,编译,汇编,链接,执行)

1.C语言的执行过程包括5个步骤:分别是:预处理,编译,汇编,链接,执行 第一步:编写C源代码,截图如下: 2.预处理,命令为:gcc -E variable.c -o variable.i(这步的作用是文件的展开和宏替换),生成的文件类型是.i类型的. 3.编译:命令为:gcc -S variable.i -o variable.s,这里的.s文件就成了会变语言,截图如下: 4.汇编,命令是:gcc -c variable.s -o variable.o,截图如下: 5,链接:命令:gcc -

GCC编译器原理(三)------编译原理三:编译过程---预处理

Gcc的编译流程分为了四个步骤: 预处理,生成预编译文件(.文件):gcc –E hello.c –o hello.i 编译,生成汇编代码(.s文件):gcc –S hello.i –o hello.s 汇编,生成目标文件(.o文件):gcc –c hello.s –o hello.o 链接,生成可执行文件:gcc hello.o –o hello 一.预处理 预编译程序读出源代码,对其中内嵌的指示字进行响应,产生源代码的修改版本,修改后的版本会被编译程序读入. 在 GNU 术语中,预处理程序叫

ROS知识(16)----如何编译时自动链接同一个工作空间的其他包的头文件(包含message,srv,action自动生成的头文件)

catkin_make编译时,往往需要自动链接同一个工作空间的其他包的头文件.否则会出现类似如下的错误: /home/xx/xx_ws/srcA_package/src/db.hpp:13:26: fatal error: B_package/alax.h: No such file or directory #include <B_package/alax.h> ^ 这需要对包进行配置,假设包A_package需要引用B_package的头文件(例如由message,srv,action自动

linux 编译时多个源文件生成一个目标文件

obj-m := target.o target-objs :=  src1.o src2.o src3.o linux 编译时多个源文件生成一个目标文件

自动生成版本信息,重新编译指定文件,一键编译IAR工程同时生成hex,bin,out文件

平台:IAR + windows_bat 1.自动生成版本信息 目的: 脚本自动更新程序svn对应的的版本号 前提: svn需要安装command line (参考 https://jingyan.baidu.com/article/a3a3f8113f89198da2eb8aed.html) 主要技术点: 具体.bat脚本主要来源于网络,文件放置在agv_dev_platform->User目录下,编译脚本将生成svnversion.h文件,文件内容仅是SVN_REVISION的一个宏,最终程

C语言预处理 编译 汇编 链接四个阶段

c程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接. 编译过程 编译过程又可以分成两个阶段:编译和会汇编. 编译 编译是读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,源文件的编译过程包含两个主要阶段: 第一个阶段是预处理阶段,在正式的编译阶段之前进行.预处理阶段将根据已放置在文件中的预处理指令来修改源文件的内容.如#include指令 就是一个预处理指令,它把头文件的内容添加到.cpp文件中.这个在编译之前修改源文件的方式提供