c++编译过程简介

  • 了解编译过程的益处
    • c++工程相关的问题
      • 什么是库?静态库和动态库又有什么区别?
      • 头文件起什么作用?
  • 编译过程简介
    • 名词:
      • 编译:把源文件中的源代码翻译成机器语言,保存到目标文件中。如果编译通过,就会把CPP转换成OBJ文件。
      • 编译单元:
        • 每个cpp就是一个编译单元,每个编译单元相互之间是独立且相互不知的。一个编译单元(Translation Unit)是指一个.cpp文件以及这所include的所有.h文件,.h文件里面的代码将会被扩展到包含它的.cpp文件里,然后编译器编译该.cpp文件为一个.obj文件,后者拥有PE(Portable Executable,即Windows可执行文件)文件格式,并且本身包含的就是二进制代码,但是不一定能执行,因为并不能保证其中一定有main函数。当编译器将一个工程里的所有.cpp文件以分离的方式编译完毕后,再由链接器进行链接成为一个.exe或.dll文件。
      • 目标文件:编译后生成的文件,以机器码的形式包含了编译单元里所有的函数和数据、导出符号表、未解决符号表、地址重定向表
        • 目标文件的类型:
          • 可重定位文件(.o、.obj文件):其中包含有适合于其它目标文件链接来创建一个可执行的或者共享的目标文件的代码和数据。每个cpp会被编译成一个.o文件
          • 共享的目标文件(库文件)
            • 这种文件存放了适合于在两种上下文里链接的代码和数据。
              • 第一种是链接程序(静态库)可把它与其它可重定位文件及共享的目标文件一起处理来创建另一个目标文件
                • 静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或者一组相关函数的代码
              • 第二种是动态链接程序(动态库)将它与另一个可执行文件及其它的共享目标文件结合到一起,创建一个进程映象
                • 动态链接库在程序执行时才被调用
          • 可执行文件
            • 一个可以被操作系统创建一个进程来执行之的文件
        • .o文件在编译后就能获得,但是库文件、可执行文件都需要在链接后才能获得
    • c++程序编译过程图
    • 编译过程
      • 作用:编译是读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,再转换为机器代码,生成目标文件(.obj)
      • 分为两个过程
        • 编译:
          • 预处理阶段
            • 宏#define
            • 条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif等。
            • 头文件包含,#include <iostream>
            • 特殊符号
              • LINE标识将被解释为当前行号(十进制

                数)

              • FILE则被解释为当前被编译的C源程序的名称。预编译程序对于在源程序中出现的这些串将用合适的值进行替换
          • 编译、优化阶段
            • 针对代码优化,不依赖具体计算机
            • 针对计算机优化
        • 汇编
          • 把汇编语言代码翻译成目标机器指令,生成目标文件(.o文件、.obj文件)。此过程会依赖机器的硬件和操作系统环境。
      • 3张表:.o文件至少要提供3张表
        • 导出符号表:即该目标文件可以提供的符号及地址
        • 未解决符号表:即找不到地址的符号的列表,告诉链接器这些符号没找到地址
        • 地址重定向表:
          • 链接的时候,链接器会为目标文件的“未解决符号表”里的符号在其他目标文件中寻找地址,但是每个目标文件的地址都是从0x0000开始的,这样直接将对方文件中符号的地址拿过来用显然会是不正确的,为了区分不同的文件,链接器在链接时就会对每个目标文件的地址进行调整。在这个例子中,假如B.obj的0x0000被定位到可执行文件的0x00001000上,而A.obj的0x0000被定位到可执行文件的0x00002000上,那么实现上对链接器来说,A.obj的导出符号地地址都会加上0x00002000,B.obj所有的符号地址也会加上0x00001000。这样就可以保证地址不会重复。
          • 因为被加上了起始地址,所以符号在自身文件中的实际地址就不对了,需要再用一张地址重定向表记录符号相对自身文件的地址
      • 例子:
    • 链接过程
      • 链接:链接程序的主要工作就是将有关的目标文件(库文件、.o文件)彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。
      • 具体工作:

        当链接器进行链接的时候,首先决定各个目标文件在最终可执行文件里的位置。然后访问所有目标文件的地址重定义表,对其中记录的地址进行重定向(加上一个偏移量,即该编译单元在可执行文件上的起始地址)。然后遍历所有目标文件的未解决符号表,并且在所有的导出符号表里查找匹配的符号,并在未解决符号表中所记录的位置上填写实现地址。最后把所有的目标文件的内容写在各自的位置上,再作一些另的工作,就生成一个可执行文件。

      • 链接方式
        • 静态链接:函数的代码将从其所在地静态链接库中被拷贝到最终的可执行程序中。这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。
        • 动态链接:函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。链接程序此时所作的只是在最终的可执行程序中

          记录下共享对象的名字以及其它少量的登记信息。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数

          代码。

    • 两种链接方式的比较
  • C/C++中提供的一些特性
    • extern:这就是告诉编译器,这个变量或函数在别的编译单元里定义了,也就是要把这个符号放到未解决符号表里面去(外部链接)。
    • static:如果该关键字位于全局函数或者变量的声明前面,表明该编译单元不导出这个函数或变量,因些这个符号不能在别的编译单元中使用(内部链接)。如果是static局部变量,则该变量的存储方式和全局变量一样,但是仍然不导出符号。
    • 默认链接属性:对于函数和变量,默认链接是外部链接,对于const变量,默认内部链接。
    • 外部链接的利弊:外部链接的符号在整个程序范围内都是可以使用的,这就要求其他编译单元不能导出相同的符号(不然就会报 duplicated external symbols)。
    • 为什么头文件里一般只可以有声明不能有定义:头文件可以被多个编译单元包含,如果头文件里面有定义的话,那么每个包含这头文件的编译单元都会对同一个符号进行定义,如果该符号为外部链接,则会导致duplicated external symbols链接错误。
    • 为什么公共使用的内联函数要定义于头文件里:因为编译时编译单元之间互不知道,如果内联被定义于.cpp文件中,编译其他使用该函数的编译单元的时候没有办法找到函数的定义,因些无法对函数进行展开(内联函数不展开,即不采用在使用处标记函数代码再跳转的方式,而是直接将代码嵌入)。所以如果内联函数定义于.cpp里,那么就只有这个.cpp文件能使用它。
    • .h中的inline 函数可以被多个cpp包含而不造成符号冲突,因为它会被直接嵌入到调用的地方,内部联结不形成外部符号,对外不可见
  • 常见编译器
  • makefile及make工具
  • 常见编译器使用方法
  • 编译错误解析

来自为知笔记(Wiz)

时间: 08-18

c++编译过程简介的相关文章

C语言-第15课 - 编译过程简介

第15课  - 编译过程简介 1. 编译器做了什么 (1)预编译: l 处理所有的注释,以空格代替. l 将所有的#define删除,并且展开所有的宏定义. l 处理条件编译指令#if,#ifdef,#elif,#else,#endif. l 处理#include,展开被包含的文件. l 保留编译器需要使用的#pragma指令. 预处理指令:gcc -E file.c -o hello.i (2)编译 l 对预处理的文件进行一系列的词法分析,语法分析和语义分析: 词法分析主要分析关键字,标示符,

第19课 编译过程简介

1. 初始编译器            广义的编译器                                                                                        你可能不知道的事… 2. 预编译:指令示例——gcc –E file.c –o file.i (1)处理所有的注释,以空格代替 (2)将所有的#define删除,并且展开所有的宏定义 (3)处理条件编译指令#if.#ifdef.#elif.#else.#endif (4)

SSCLI编译过程简介

前文演示了编译SSCLI最简便的方法(在Windows下): 在“Visual Studio 2005 Command Prompt”下,进入SSCLI的根目录: 运行 env.bat 脚本准备环境: 运行 buildall.cmd 脚本开始编译过程. env.bat设置了当前SSCLI的运行环境,命令的语法是:`env [option]`,其中[option]可以是debug.checked和free,各个环境选项说明如下表: 选项 说明 debug 关闭代码优化设置,启用调试用代码(一般是通

C语言编译过程简介

刚开始接触编程的时候,只知道照书敲敲代码,一直都不知道为什么在windows平台下代码经过鼠标那样点击几下,程序的结果就会在那个黑色的屏幕上.现在找了个机会将C语言的编译原理做一下小小的总结,这样也能为以后我们进军linux编程做一些准备工作,现在这里和大家一起分享分享.O(∩_∩)O~ 讲到编译原理,我觉得首先我们得明白一些基本概念. 编辑器:我们编写代码的一些窗口,如:记事本.word.notepad 等. 编译器:检查用户代码的一些语法错误并且将其编译成汇编代码. 汇编器:将编译出来的文件

编译过程

编译过程简介: 预编译:gcc -E file.c -o file.i 处理注释,以空格代替 将宏定义展开 处理条件编译指令 处理#include,展开被包含的文件 保留编译器需要使用的#pragma指令 编译: gcc -S file.i -o file.s 对预处理文件进行词法分析,语法 分析,语义分析 汇编:gcc -c file.s -o hello.o 将汇编代码翻译成机器码 链接: 将各个模块之间的相互引用的部分处理好,使得各个模块之间能够正确的衔接.将各个独立的模块链接成可执行的程

gcc 学习笔记(一) - 编译C程序 及 编译过程

一. C程序编译过程 编译过程简介 : C语言的源文件 编译成 可执行文件需要四个步骤, 预处理 (Preprocessing) 扩展宏, 编译 (compilation) 得到汇编语言, 汇编 (assembly) 得到机器码, 连接 (linking) 得到可执行文件; -- 查看每个步骤的编译细节 : "-E" 对应 预处理, "-S" 对应 编译, "-c" 对应 汇编, "-O" 对应 连接; -- 每个步骤对应的工

编译过程中,termcap.h 文件找不到路径 licli.a终于生成

编译过程中,termcap.h      文件找不到路径 查看是linux  源码下找不到termcap.h文件 安装了所有关于*cap*的源码包也不起作用 今天终于解决了这个问题,搜termcap.h  发现一篇文章,如下 ----------------------------------------------------------------------------------------- 安装minicom2.3出现termcap.h错误解决方法 2010-05-06 17:12:

嵌入式之:Linux下文件编译过程

本文主要三个部分:1.GNU GCC简介 2.C/C++交叉编译器arm-elf-gcc 3.make文件,用于工程管理 部分一:GNU GCC简介: 该编译器基本功能: (1)输出预处理后的文件(展开头文件和替换宏) (2)输出.s的汇编文件 (3)输出二进制目标文件 (4)输出.o可执行文件 (5)转换文件格式 (6)生成静态库文件 工具: arm-elf-gcc:她是前端程序通过调用其他程序实现把code编译为可执行文件 arm-elf-as:将汇编转为ELF(executable and

u-boot的启动、编译过程和命令添加

MCU:s5pv210 开发板:unsp210 u-boot:1.3.4 一.简介 U-Boot是一种支持多架构,多操作系统的Bootloader(启动引导程序) u-boot目前最新版本是:http://ftp.denx.de/pub/u-boot/ 二.启动过程 嵌入式Bootloader的启动过程可以分为单阶段(Single-Stage)和多阶段(Multi-Stage) 通常多阶段的Bootloader能够提供更复杂的功能,及更好的可读性和移植性. 从外部存储设备上启动的Bootload