C++内部链接与外部链接
来源:互联网 发布:java 网络请求框架 编辑:程序博客网 时间:2024/05/21 17:59
你曾经碰到的问题:
1.为什么有时会出现aaa已在bbb中重定义的错误?
2.为什么有时会出现无法解析的外部符号?
3.为什么有的内联函数的定义需要写在头文件中?
4.为什么对于模板,声明和定义都要写在一起?
编译单元
什么是编译单元呢?简单来说一个cpp文件就是一个编译单元。
编译单元:当一个c或cpp文件在编译时,预处理器首先递归包含头文件,形成一个含有所有 必要信息的单个源文件,这个源文件就是一个编译单元。
事实上编译每个编译单元(.cpp)时是相互独立的,即每个cpp文件之间是不知道对方的存在的(不考虑#include “xxx.cpp" 这种奇葩的写法)
编译器会分别将每个编译单元(.cpp)进行编译,生成相应的obj文件
然后链接器会将所有的obj文件进行链接,生成最终可执行文件。
内部链接与外部链接
那么什么内部链接和外部链接又是什么呢?
我们知道C++中声明和定义是可以分开的
例如 我们可以一个函数声明定义放在b.cpp中,在a.cpp只需再声明一下这个函数,就可以在a.cpp中使用这个函数了
a.cpp
void show();int main(){ show(); return 0;}
b.cpp
#include <iostream>void show(){ std::cout << "Hello" << std::endl;}
而通过之前的了解,我们知道每个编译单元间是相互独立不知道彼此的存在的
那么a.cpp又是如何知道show函数的定义的呢
其实在编译一个编译单元(.cpp)生成相应的obj文件过程中
编译器会将分析这个编译单元(.cpp)
将其所能提供给其他编译单元(.cpp)使用的函数,变量定义记录下来。
而将自己缺少的函数,变量的定义也记录下来。
所以可以认为a.obj和b.obj记录了以下的信息
然后在链接器连接的时候就会知道a.obj需要show函数定义,而b.obj中恰好提供了show函数的定义,通过链接,在最终的可执行文件中我们能看到show函数的运行。
好了让我们看下 内部链接和外部链接比较正式的定义吧
内部连接:如果一个名称对编译单元(.cpp)来说是局部的,在链接的时候其他的编译单元无法链接到它且不会与其它编译单元(.cpp)中的同样的名称相冲突。例如static函数,inline函数等(注 : 用static修饰的函数,本限定在本源码文件中,不能被本源码文件以外的代码文件调用。而普通的函数,默认是extern的,也就是说,可以被其它代码文件调用该函数。)
外部连接:如果一个名称对编译单元(.cpp)来说不是局部的,而在链接的时候其他的编译单元可以访问它,也就是说它可以和别的编译单元交互。 例如变量就是外部链接, 全局变量。
那么回到最初的问题:
1. 为什么有时会出现aaa已在bbb中重定义的错误?
答: 你可能在不同的cpp中重复定义了一个具有外部链接的函数或变量,链接器在链接时找到了多个一样的函数或变量定义。
2. 为什么有时会出现无法解析的外部符号?
答:你可能只提供了函数或变量的声明,没有提供其定义,或者声明和定义的函数原型不一致,链接器没有找到其定义在哪里,所以在链接环节出现了无法解析的外部符号的错误。
3. 为什么有的内联函数的定义需要写在头文件中呢?
答:因为内链函数是内部链接的,如果你在b.cpp中定义这个函数,那么在a.cpp中即使有这个函数声明,但由于内联函数是内部链接的,所以b.cpp不会提供其定义。所以在链接时a.obj无法找到这个函数的定义,便会出现无法解析的外部符号的错误
4.为什么对于模板,声明和定义都要写在一起呢?
答:我们假设我们有如下结构的代码
a.h
#pragma oncetemplate<typename T>class A{public: A(const T &t);};
a.cpp
#include "a.h"#include <iostream>template<typename T>A<T>::A(const T &t){ std::cout << t << std::endl;}
main.cpp
#include "a.h"int main(){ A<int> a(5); return 0;}
那么程序能否正常运行呢?答案是不能 我们首先来分析一下编译器在编译main.cpp时,只有声明,发现其缺少A<int>::a(const int& t)的定义 ,因为它不在a.h里面, 于是编译器只好寄希望于连接器, 希望它能够在其他.obj里找到定义, 而在编译器编译a.cpp时,没有用到A<int> , 模板只有被用到的时候才会被实例化, 每个编译单元是独立的,它也不知道main.cpp用了A<int> ,所以它不会提供定义,编译出来的a.obj文件中关于A 的一行二进制代码也没有,这样在链接时main.obj无法找到A<int>::a(const int& t)的定义,就会出现无法解析的外部符号的错误LNK1120 (注意, 在a.cpp 中加入一个函数用到A, void f2(){ A<int > a(222); } ,则此问题解决 )
5.宏是内部链接还是外部链接
答:都不是,宏在预处理环节时就被替换掉了,而内部链接与外部链接是针对编译环节与链接环节而言的
Created by 黄强
- 内部链接与外部链接
- 内部链接与外部链接
- 内部链接与外部链接
- 外部链接与内部链接
- 内部链接与外部链接
- 链接之外部链接与内部链接
- C++ 内部链接与外部链接
- C++ 内部链接与外部链接
- C++内部链接与外部链接
- C++内部链接与外部链接
- C++编译与链接-浅谈内部链接与外部链接
- 内部链接和外部链接
- c++ 内部链接 外部链接
- c++ 内部链接 外部链接
- 内部链接和外部链接
- 内部链接和外部链接
- static inline与内部、外部链接对象
- C标识符的链接(外部链接,内部链接和无链接)
- Maven详解
- lnmp环境 开启pathinfo
- hasMap 和 hasTable 与 Collection 和ArrayList
- iframe,frameset,frame
- mongodb dirver for java【聚合】
- C++内部链接与外部链接
- Go 语言在实际项目应用的技术文档
- Eclipse中创建Maven项目时,报错提示:“a pom xml file already exists in the destination folder ”
- 第十八周:[Leetcode]240. Search a 2D Matrix II
- weblogic集群代理报错
- iOS UIScrollView内部子控件添加约束的注意点
- jQuery笔记
- AngularJS学习笔记
- JavaScript入门