c++内联(inline)函数不报重定义错误分析

1 问题背景

  • 关键字inline用于建议编译器在调用处展开被修饰的函数,但最终是否展开取决于编译器的行为
    • gcc配置参数-O0时不会进行编译优化,inline关键字不生效
    • gcc配置参数-O2时会进行编译优化,inline关键字生效
  • C/C++语法中,如果变量、函数在同一个工程中被多次定义,链接期间会报类似“对 xxx 多重定义”的错误;
  • inline函数如果会在多处被调用,则需要将函数的定义写在头文件中
    • 注:inline函数的声明和定义分别在头文件和源文件中,并且在其他文件中被调用时,链接期间编译器会报“对 xxx 未定义的引用”错误。

2 问题描述

  看到后面两条规则,大家可能会很疑惑

“为什么inline关键字修饰的函数定义在头文件中(函数可能会被多次定义),编译器不会报“对 xxx 多重定义”的错误呢?”

  很容易猜到,一定是编译器对被inline修饰的函数做了特殊处理,具体做了什么样的特殊处理?让我们来一看究竟…

3 问题分析

  在分析问题之前,我们需要了解两个概念强符号弱符号。我们不展开讲强符号弱符号的概念,详情可以参考弱符号与强符号概念强符号和弱符号,这里只需要了解强符号弱符号的主要区别即可

  • 强符号不允许被多次定义;
  • 强符号和弱符号同时存在,选择强符号;
  • 同时存在多个弱符号,选择占用空间最大的一个;

  想必大家已经猜到了,inline函数可能是个弱符号,所以链接期间不会报“对 xxx 多重定义”的错误。我们来通过一个demo看看实际情况是怎样的。
  下面两个.cpp文件,除Function()inline修饰符外其他内容完全一致

/* NormalMain.cpp */
#include <cstdio>

void Function()
{
    printf("[Function]========= Get!!!\n");
}

int main() {
    Function();
}
/* InlineMain.cpp */
#include <cstdio>

inline void Function()
{
    printf("[Function]========= Get!!!\n");
}

int main() {
    Function();
}

编译后部分汇编码如下(未贴出来的部分,两个文件基本一致)

NormalMain.cpp编译结果

	.file	"NormalMain.cpp"
	.section	.rodata
.LC0:
	.string	"[Function]========= Get!!!"
	.text
	.globl	_Z8Functionv
	.type	_Z8Functionv, @function
_Z8Functionv:
;...

InlineMain.cpp编译结果

	.file	"InlineMain.cpp"
	.section	.rodata
.LC0:
	.string	"[Function]========= Get!!!"
	.section	.text._Z8Functionv,"axG",@progbits,_Z8Functionv,comdat
	.weak	_Z8Functionv
	.type	_Z8Functionv, @function
_Z8Functionv:
;...

  很容易发现,inline修饰的Function()编译结果是.weak--弱符号,而没有被inline修饰的Function()编译结果是.globl--全局符号(强符号),所以我们前面的猜测inline函数可能是个弱符号,所以链接期间不会报错是正确的。

4 结论

  inline函数是个弱符号,重复定义以后链接期间不会报“对 xxx 多重定义”的错误


5 避坑

  在编译器优化参数关闭的情况下(或因其他原因导致编译器没有做优化),由于inline函数编译后是个弱符号,所以建议谨慎使用inline修饰函数,因为可能会有
坑从哪来?
  编译器优化开关关闭时,inline函数可能会被同名的其它函数替代,从而影响业务逻辑的正确性。如下代码

/* InlineMain.cpp */
#include <cstdio>

inline void Function()
{
    printf("[Function]========= Get!!!\n");
}

int main() {
    Function();
}
/* FunctionDef.cpp */
#include <cstdio>

void Function()
{
    printf("[Another Function]========= Get!!!\n");
}

  运行结果为

[Another Function]========= Get!!!

运行结果与预期不符,因为inline函数(编译后为弱符号)被替换了。

  编译器优化开关打开时,运行结果正常不存在问题。

[Function]========= Get!!!
  • 9
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值