编译器把一个cpp编译为目标文件的时候,除了要在目标文件里写入cpp里包含的数据和代码,还要至少提供3个表:未解决符号表导出符号表地址重定向表

  1. 未解决符号表提供了所有在该编译单元里引用但是定义并不在本编译单元里的符号及其出现的地址。

  2. 导出符号表提供了本编译单元具有定义,并且愿意提供给其他编译单元使用的符号及其地址。

  3. 地址重定向表提供了本编译单元所有对自身地址的引用的记录。

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

注意

  extern:这是告诉编译器,这个符号在别的编译单元里定义,也就是要把这个符号放到未解决符号表里去。(外部链接)

  static:如果该关键字位于全局函数或者变量的声明的前面,表明该编译单元不导出这个函数/变量的符号。因此无法在别的编译单元里使用。(内部链接)。如果是static局部变量,则该变量的存储方式和全局变量一样,但是仍然不导出符号。

  默认链接属性:对于函数和变量,模认外部链接,对于const变量,默认内部链接。(可以通过添加extern和static改变链接属性)

  外部链接的利弊:外部链接的符号,可以在整个程序范围内使用(因为导出了符号)。但是同时要求其他的编译单元不能导出相同的符号(不然就是duplicated external simbols)

  内部链接的利弊:内部链接的符号,不能在别的编译单元内使用。但是不同的编译单元可以拥有同样名称的内部链接符号。

  为什么头文件里一般只可以有声明不能有定义:头文件可以被多个编译单元包含,如果头文件里有定义,那么每个包含这个头文件的编译单元就都会对同一个符号 进行定义,如果该符号为外部链接,则会导致duplicated external simbols。因此如果头文件里要定义,必须保证定义的符号只能具有内部链接。

  为什么常量默认为内部链接,而变量不是:这就是为了能够在头文件里如const int n = 0这样的定义常量。由于常量是只读的,因此即使每个编译单元都拥有一份定义也没有关系。如果一个定义于头文件里的变量拥有内部链接,那么如果出现多个编译 单元都定义该变量,则其中一个编译单元对该变量进行修改,不会影响其他单元的同一变量,会产生意想不到的后果。

  为什么函数默认是外部链接:虽然函数是只读的,但是和变量不同,函数在代码编写的时候非常容易变化,如果函数默认具有内部链接,则人们会倾向于把函数定义在头文件里,那么一旦函数 被修改,所有包含了该头文件的编译单元都要被重新编译。另外,函数里定义的静态局部变量也将被定义在头文件里。

  为什么类的静态变量不可以就地初始化:所谓就地初始化就是类似于这样的情况

class A {
     static char msg[] = "aha";
};

由于class的声明通常是在头文件里,如果允许这样做,其实就相当于在头文件里定义了一个非const变量。

  为什么类的静态常量也不可以就地初始化:因为这相当于在头文件里定义了const对象。作为例外,int/char等可以进行就地初始化,是因为这些变量可以直接被优化为立即数,就和宏一样。

  在C++里,头文件定义一个const对象会怎么样:一般不会怎么样,这个和C里的在头文件里定义const int一样,每一个包含了这个头文件的编译单元都会定义这个对象。但由于该对象是const的,所以没什么影响。但是:有2种情况可能破坏这个局面:

  1. 如果涉及到对这个const对象取地址并且依赖于这个地址的唯一性,那么在不同的编译单元里,取到的地址可以不同。(但一般很少这么做)
  2. 如果这个对象具有mutable的变量,某个编译单元对其进行修改,则同样不会影响到别的编译单元。

  为什么公共使用的内联函数要定义于头文件里:因为编译时编译单元之间互相不知道,如果内联函数被定义于.cpp文件中,编译其他使用该函数的编译单元的时候没有办法找到函数的定义,因此无法对函数进行展开。所以说如果内联函数定义于.cpp文件里,那么就只有这个cpp文件可以是用这个函数。

  头文件里内联函数被拒绝会怎样:如果定义于头文件里的内联函数被拒绝,那么编译器会自动在每个包含了该头文件的编译单元里定义这个函数并且不导出符号。

  如果被拒绝的内联函数里定义了静态局部变量,这个变量会被定义于何处:早期的编译器会在每个编译单元里定义一个,并因此产生错误的结果,较新的编译器会解决这个问题,手段未知。

  为什么export关键字没人实现:export要求编译器跨编译单元查找函数定义,使得编译器实现非常困难。

c/c++编译和链接过程的更多相关文章

  1. GCC编译和链接过程

    GCC(GNU Compiler Collection,GNU编译器套件),是由 GNU 开发的编程语言编译器.它是以GPL许可证所发行的自由软件,也是 GNU计划的关键部分.GCC原本作为GNU操作 ...

  2. C++, Java和C#的编译、链接过程解析

    总是感觉java是解释性语言,转载下一篇感觉写的容易理解的文章 转自 http://www.cnblogs.com/rush/p/3155665.html 1.1.1 摘要 我们知道计算机不能直接理解 ...

  3. Linux中程序的编译和链接过程

    1.从源码到可执行程序的步骤:预编译.编译.链接.strip 预编译:预编译器执行.譬如C中的宏定义就是由预编译器处理,注释等也是由预编译器处理的. 编译: 编译器来执行.把源码.c .S编程机器码. ...

  4. C/C++编译和链接过程详解 (重定向表,导出符号表,未解决符号表)

    详解link  有 些人写C/C++(以下假定为C++)程序,对unresolved external link或者duplicated external simbol的错误信息不知所措(因为这样的错 ...

  5. C语言编译和链接过程

    1.程序的编译  一般而言,大多数编译系统都提供编译驱动程序(complier driver),根据用户需求调用语言预处理器,编译器,汇编器和链接器.例如有如下历程://main.c void swa ...

  6. (转载) C/C++编译和链接过程详解 (重定向表,导出符号表,未解决符号表)

    转载http://blog.csdn.net/neo_ustc/article/details/9024839 有 些人写C/C++(以下假定为C++)程序,对unresolved external ...

  7. c 编译和链接过程

    详解link  有 些人写C/C++(以下假定为C++)程序,对unresolved external link或者duplicated external simbol的错误信息不知所措(因为这样的错 ...

  8. Linux | GCC如何实现代码编译&&汇编&&链接过程

      正文: 每次我们程序员所写的 代码 是给程序员看的呢?还是给电脑看的?其实我们所写的代码只是我们程序员之间交流的一样特殊语言,电脑是看不懂的.那么我们如何实现人机交流呢?这就不得不请出我们我们今天 ...

  9. C++编译与链接(1)-编译与链接过程

    大家知道计算机使用的一系列的1和0 那个一个C++语言程序又是如何从一个个.h和.cpp文件变成包含1和0的可执行文件呢? 可以认为有以下的几个环节 源程序->预处理->编译和优化-> ...

随机推荐

  1. ubuntu14.04下搜狗输入法不能输入中文问题解决

    解决方法如下:   一.重启搜狗输入法 通过下面的两个命令重启搜狗输入法 ~$ killall fcitx  ~$ killall sogou-qinpanel   二.检查修复安装依赖 ~$ sud ...

  2. 重载方法写delete请求

    #encoding=utf-8#__author__="Lanyangyang" import unittestimport requestsimport json # This ...

  3. Centos7部署hadoop 3

    一:ssh免密登录: 1)vim /etc/ssh/sshd_config去掉注释或添加 RSAAuthentcation yes PubkeyAuthentication yes # Authent ...

  4. 【重大更新】DevExpress WinForms v18.2新版亮点(七)

    买 DevExpress Universal Subscription  免费赠 万元汉化资源包1套! 限量15套!先到先得,送完即止!立即抢购>> 行业领先的.NET界面控件2018年第 ...

  5. LSTM-自然语言建模

    说到自然语言,我就会想到朴素贝叶斯,贝叶斯核心就是条件概率,而且大多数自然语言处理的思想也就是条件概率. 所以我用预测一个句子出现的概率为例,阐述一下自然语言处理的思想. 处理思想-概率 句子,就是单 ...

  6. ChinaCock界面控件介绍-TCCImageViewerForm

    有多个图片,左右滑动可以切换,通过手势还可以放大.缩小查看,象常见的相册,就是这样子实现效果. 现在,我们有了TCCImageViewerForm组件,也可以轻松实现这样的场景应用. 现在看看TCCI ...

  7. python 递归函数操作方法

    .递归 是指函数/过程/子程序在运行过程序中直接或间接调用自身而产生的重入现象.在计算机编程里,递归指的是一个过程:函数不断引用自身,直到引用的对象已知.使用递归解决问题,思路清晰,代码少.但是在主流 ...

  8. Centos7 使用Docker搭建Oracle测试环境

    1.更新yum yum update 2.安装Docker yum install docker 安装完成后查看Docker的版本: docker version 查看Docker的信息: docke ...

  9. sql,取得当前系统时间,算时间区间

    mysql: SELECT * from (SELECT H_TEMPERATURE FROM WENSHIDU  WHERE TH_TIME >=date_sub(NOW(), interva ...

  10. python 实现 KNN 分类器——手写识别

    1 算法概述 1.1 优劣 优点:进度高,对异常值不敏感,无数据输入假定 缺点:计算复杂度高,空间复杂度高 应用:主要用于文本分类,相似推荐 适用数据范围:数值型和标称型 1.2 算法伪代码 (1)计 ...