c/c++编译和链接过程
编译器把一个cpp编译为目标文件的时候,除了要在目标文件里写入cpp里包含的数据和代码,还要至少提供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种情况可能破坏这个局面:
- 如果涉及到对这个const对象取地址并且依赖于这个地址的唯一性,那么在不同的编译单元里,取到的地址可以不同。(但一般很少这么做)
- 如果这个对象具有mutable的变量,某个编译单元对其进行修改,则同样不会影响到别的编译单元。
为什么公共使用的内联函数要定义于头文件里:因为编译时编译单元之间互相不知道,如果内联函数被定义于.cpp文件中,编译其他使用该函数的编译单元的时候没有办法找到函数的定义,因此无法对函数进行展开。所以说如果内联函数定义于.cpp文件里,那么就只有这个cpp文件可以是用这个函数。
头文件里内联函数被拒绝会怎样:如果定义于头文件里的内联函数被拒绝,那么编译器会自动在每个包含了该头文件的编译单元里定义这个函数并且不导出符号。
如果被拒绝的内联函数里定义了静态局部变量,这个变量会被定义于何处:早期的编译器会在每个编译单元里定义一个,并因此产生错误的结果,较新的编译器会解决这个问题,手段未知。
为什么export关键字没人实现:export要求编译器跨编译单元查找函数定义,使得编译器实现非常困难。
c/c++编译和链接过程的更多相关文章
- GCC编译和链接过程
GCC(GNU Compiler Collection,GNU编译器套件),是由 GNU 开发的编程语言编译器.它是以GPL许可证所发行的自由软件,也是 GNU计划的关键部分.GCC原本作为GNU操作 ...
- C++, Java和C#的编译、链接过程解析
总是感觉java是解释性语言,转载下一篇感觉写的容易理解的文章 转自 http://www.cnblogs.com/rush/p/3155665.html 1.1.1 摘要 我们知道计算机不能直接理解 ...
- Linux中程序的编译和链接过程
1.从源码到可执行程序的步骤:预编译.编译.链接.strip 预编译:预编译器执行.譬如C中的宏定义就是由预编译器处理,注释等也是由预编译器处理的. 编译: 编译器来执行.把源码.c .S编程机器码. ...
- C/C++编译和链接过程详解 (重定向表,导出符号表,未解决符号表)
详解link 有 些人写C/C++(以下假定为C++)程序,对unresolved external link或者duplicated external simbol的错误信息不知所措(因为这样的错 ...
- C语言编译和链接过程
1.程序的编译 一般而言,大多数编译系统都提供编译驱动程序(complier driver),根据用户需求调用语言预处理器,编译器,汇编器和链接器.例如有如下历程://main.c void swa ...
- (转载) C/C++编译和链接过程详解 (重定向表,导出符号表,未解决符号表)
转载http://blog.csdn.net/neo_ustc/article/details/9024839 有 些人写C/C++(以下假定为C++)程序,对unresolved external ...
- c 编译和链接过程
详解link 有 些人写C/C++(以下假定为C++)程序,对unresolved external link或者duplicated external simbol的错误信息不知所措(因为这样的错 ...
- Linux | GCC如何实现代码编译&&汇编&&链接过程
正文: 每次我们程序员所写的 代码 是给程序员看的呢?还是给电脑看的?其实我们所写的代码只是我们程序员之间交流的一样特殊语言,电脑是看不懂的.那么我们如何实现人机交流呢?这就不得不请出我们我们今天 ...
- C++编译与链接(1)-编译与链接过程
大家知道计算机使用的一系列的1和0 那个一个C++语言程序又是如何从一个个.h和.cpp文件变成包含1和0的可执行文件呢? 可以认为有以下的几个环节 源程序->预处理->编译和优化-> ...
随机推荐
- java基础入门系列1
学java之前先了解下window系统的的一些常识: #常用windows快捷键 ctrl+x:剪切 ctrl+z:撤销 ctrl+A:全选 ctrl+V:黏贴 windows+d:回到桌面 Wind ...
- DevExpress v18.1新版亮点——Data Access篇
用户界面套包DevExpress v18.1日前正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了DevExpress Data Access v18.1 的新功能,快来下载试用新版本 ...
- springMVC拦截css与js等资源文件的解决
写了一个demo的ssm,使用jetty容器跑的,但是在页面的时候总是发现访问资源出现404. 换了多种写法不见效. 偶然发现日志中请求被springMVC拦截了,气死我了. 解决方式: Spring ...
- 安装连接mysql8时候遇到的问题以及解决(转)
官网下载mysql8的安装包: https://dev.mysql.com/downloads/ 下一步安装即可. mysql8增加了传说中的安全性校验 遇到的几个问题: 1.natcat连接不上.参 ...
- 通过powerdesiner导出sql,通过sql转mysql为oracle
1.导出sql文件 Database-->generate database-->确定 执行完就可以看到生成的语句了 2.将mysql的PDM转换为oracle File-->rev ...
- 18-09-08 关于Linux 的安装遇到的一些小坑
具体参考我的有道笔记 备注 那个网络问题已经解决 先自动选择打上勾 然后在进行选择 并且正确输入 IP地址之类的 ====用utrallo 制作centos7.0 报错 以下是新的工具有效===== ...
- android 8.0 intent安装apk失败屏幕闪过
需要做两处设置: 1.android8.0要加一条权限: <uses-permission android:name="android.permission.REQUEST_INSTA ...
- 记第十四届省赛参赛体会&第十三届
emmm....时间还是很久远了 还是流水账 这次比赛我还是挺开心的 因为感觉我们余神就是一把宝剑,然后我是她的Buff 前面四道题就挺顺利都1A过了,十年余神就是强无敌呀 最后两分钟过了第五题,银牌 ...
- yum配置Linux的Web服务器
1.打开终端:输入su -root用于切换至root用户,目的是为了取得权限2.安装步骤如下(1)安装文件[root@localhost ~]# yum -y install httpd.i686[r ...
- 【linux】ARM板子开启浮点和neon加速
参考 1. ARM平台NEON指令的编译和优化; 2. 交叉编译器 arm-linux-gnueabi 和 arm-linux-gnueabihf 的区别; 3. https://blog.csdn. ...