C++中内部链接和外部链接(关联问题:static、inline的作用;重定义问题;无法解析的外部符号;模板声明和定义为什么要写在一起)

2021年01月19日 周二 天气晴 【不悲叹过去,不荒废现在,不惧怕未来】


本文转载自:https://zhuanlan.zhihu.com/p/150001991 ,有改动。

搞明白内部链接和外部链接,之前的很多问题诸如:static、inline的作用;重定义问题;无法解析的外部符号;模板声明和定义为什么要写在一起,都能比较容易理解了,以下是正文。


1. 编译单元

简单地,一个cpp文件就是一个编译单元。定义:当一个c或者cpp文件在编译时,预处理器首先递归包含头文件,形成一个含有所有必要信息的单个源文件,这个源文件就是一个编译单元。

编译每个编译单元时互相独立,即每个cpp文件之间不知道对方的存在(一般不这样写:#include“xxx.cpp”),编译器会分别将每个编译单元进行编译,生成相应的obj文件,然后生成最终的可执行文件。

2. 内部链接和外部链接

C++中声明和定义是可以分开的,例如我们在B.cpp中声明并定义一个函数func_b(),在A.cpp中只需要声明一下这个函数,就可以在A.cpp中使用这个函数了。

然而每个编译单元之间是相互独立,不知道彼此存在的,但A.cpp却知道func_b()的定义。这是因为,在编译一个编译单元生成相应的obj文件过程中,编译器会分析这个编译单元,将其所能提供给其他编译单元的函数、变量定义记录下来,而将自己缺少的函数、变量的定义也记录下来。

也就是说,A.obj记录了“我能提供main函数定义,我需要func_b()函数定义”,而B.obj记录了“我能提供func_b()函数的定义”,通过链接,在最终的可执行文件中我们能看到func_b()函数的运行。

内部链接——如果一个名称对编译单元来说是局部的,在链接的时候其他编译单元无法链接到它且不会与其他编译单元中的同样名称相冲突。(例如被关键字static,inline标识)

外部链接——如果一个名称对编译单元来说不是局部的,而在链接的时候其他的编译单元可以访问它,也就是说它可以和别的编译单元交互。

相应地有编程中常见的问题如下:

  • aaa在BBB中重定义
    在不同的cpp中重复定义了一个具有外部链接的函数或变量,链接器在链接时找到了多个一样的函数或变量定义。

  • 无法解析的外部符号
    只提供了函数或变量的声明没有提供其定义或者声明和定义的函数原型不一致,链接器没有找到其定义在哪里。

  • 部分内联函数的定义需要写在头文件中
    内联函数是内部链接的。

  • 对于模板,声明和定义都要写在一起
    假设有如下代码:

test.h
#pragma once
template<typename T>
class Test
{
public:
Test(const T& t);
};

test.cpp
#include "A.h"
#include <iostream>
template<typename T>
Test<T>::Test(const T& t)
{
 std::cout << t << std::endl;
}

main.cpp
#include "test.h"
int main()
{
 Test<int> a(5);
 return 0;
}

代码是不能正常运行的,因为编译main.cpp的时候,只有模板的声明,并没有Test::Test(const int& t)的定义,于是编译器寄希望于链接器,希望它能够在其他的.obj中找到定义,而在编译器编译test.cpp的时候,并没有用到Test类,只是给出了构造函数的定义,而模板只有被用到时才会实例化,test.cpp并不知道main.cpp用了Test(上面说过了),所以它不会提供定义。解决的方法是在test.cpp中加入一个函数用到Test,或者直接将模板的定义和声明都放在头文件中。

宏是内部链接?外部链接?
宏在预处理环节被替换掉了,而内部链接和外部链接都是针对编译环节和链接环节的。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值