关于inline这个关键字,听到强调得最多的是,它只是一种对于编译器的建议,而非强制执行的限定。

但事实上,即使这个优化最终由于函数太过复杂的原因没有达成,加上inline关键字(还有在类定义中直接定义的函数也相当于加上了inline关键字)还是会带来一些区别的。

参看C++11标准文档里面的描述:

A function declaration (8.3.5, 9.3, 11.3) with an inline specifier declares an inline function. The inline
specifier indicates to the implementation that inline substitution of the function body at the point of call
is to be preferred to the usual function call mechanism. An implementation is not required to perform this
inline substitution at the point of call; however, even if this inline substitution is omitted, the other rules
for inline functions defined by 7.1.2 shall still be respected.

这里所谓的other rules具体如下:

An inline function shall be defined in every translation unit in which it is odr-used and shall have exactly
the same definition in every case (3.2). [ Note: A call to the inline function may be encountered before its
definition appears in the translation unit. — end note ] If the definition of a function appears in a translation
unit before its first declaration as inline, the program is ill-formed. If a function with external linkage is
declared inline in one translation unit, it shall be declared inline in all translation units in which it appears;
no diagnostic is required. An inline function with external linkage shall have the same address in all
translation units. A static local variable in an extern inline function always refers to the same object.
A string literal in the body of an extern inline function is the same object in different translation units.
[ Note: A string literal appearing in a default argument is not in the body of an inline function merely
because the expression is used in a function call from that inline function. — end note ] A type defined
within the body of an extern inline function is the same type in every translation unit.

这里最关键的就是一个内联的函数,可以在多个cpp文件里面都有定义(回想一下普通函数如果这么干的话会有multiple definition的错误),标准明确了多个cpp文件的定义一定要一致,

但是编译器层面并不检查。

要理解An inline function with external linkage shall have the same address in all translation units. 这句话,可能需要对于链接过程有一定的理解。(深入理解计算机系统(csapp)第7章)。还可以看一下http://blog.copton.net/articles/linker/

这里简单表述就是,C++程序的每一个编译单元(cpp文件),编译完成之后生成一个.o文件,链接过程就是将这些.o文件合成一个可执行文件。

.o文件里是哪些内容呢?很多,关心的主要是以下几项

.text:代码段,包括这个cpp文件里定义的所有函数得到的字节码

.data:全局已初始化数据

.bss:全局未初始化数据

.reltext:引用的外部函数符号(比如我们会在引用外部函数或变量的时候有一个声明)

.reldata引用的外部变量

合成过程需要将各个.o文件的这几个部分聚合到一起:1重定位,聚合之后变量、函数都要重新排布,当然需要重定位2、将.reltext .data节里引用的外部函数,变量等赋予最终重定位之后的地址

看到这里,就能够大概理解,如果两个cpp文件恰好定义了同一个函数,会造成它们生成的.o文件在聚合的时候不知道取哪个定义,那么其它引用这个函数的地方也不知道重定位到哪,

所以会出现multiple definition的错误。而根据上面对于inline内联函数的表述,可以发现,它事实上赋予这种函数一个特别的属性,就是在多个.o文件里都定义了同一个内联函数的时候,

(这里当然不是成功内联的情形,因为那样的话根本只是插入代码段,连函数符号都没有了,更不用担心重定义了),链接器确保只从中选取一个作为最终的符号地址,这样就保证了

不会由重定义的情况出现了。

C++ inline weak symbol and so on的更多相关文章

  1. GNU的strong symbol和weak symbol

    首先,同样的原型的两个函数在连个不同的c文件中都有定义,把这两个c文件编译.连接在一起,也没有什么错误.原因就是因为,gcc中有一个strong symbol和weak symbol的概念.默认函数定 ...

  2. [原] inline operator delete & DLL boundary

    很久以前写在百度空间的这篇文章: [百度空间] [原] 全局operator delete重载到DLL 首先,纠正一个词“重载”,operator new/delete是替换(replacement) ...

  3. gcc/g++中weak弱符号及alias别名

    最近查看linux内核代码时,表现了一些编译器选项如__attribute_((weak)).__attribute__( (alias("target"))),一开始不了解,后来 ...

  4. C语言之强化,弱化符号weak

    一.概述 在C语言中,函数和初始化的全局变量(包括显示初始化为0)是强符号,未初始化的全局变量是弱符号. 对于它们,下列三条规则使用: ① 同名的强符号只能有一个,否则编译器报"重复定义&q ...

  5. weak alias

    Weak Alias 跟 Weak Reference 完全没有任何关系,不过是我在看到 Weak Reference 的时候想到的而已. Weak Alias 是 gcc 扩展里的东西,实际上是函数 ...

  6. 弱符号__attribute__((weak))

    弱符号是什么? 弱符号: 若两个或两个以上全局符号(函数或变量名)名字一样,而其中之一声明为weak symbol(弱符号),则这些全局符号不会引发重定义错误.链接器会忽略弱符号,去使用普通的全局符号 ...

  7. __attribute__((weak, alias())))

    参考gcc的reference: 弱符号: 若两个或两个以上全局符号(函数或变量名)名字一样,而其中之一声明为weak symbol(弱符号),则这些全局符号不会引发重定义错误.链接器会忽略弱符号,去 ...

  8. 5.24 Declaring Attributes of Functions【转】

    转自:https://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Function-Attributes.html 5.24 Declaring Attributes o ...

  9. GNU C/C++ __attributes__ GCC中的弱符号与强符号

    最近在看一些源代码,遇到了一些使用__attribute__修饰函数和变量的属性方面的代码,不是太了解,很是汗颜,再此做个总结:   GCC使用__attribute__关键字来描述函数,变量和数据类 ...

随机推荐

  1. Gradle 教程:第一部分,安装【翻译】

    原文地址:http://rominirani.com/2014/07/28/gradle-tutorial-part-1-installation-setup/ 在这篇教程里,我们将主要讲解如何在我们 ...

  2. robotframework笔记18

    测试执行 如何创建测试套件结构解析 执行测试数据,如何继续执行一个测试用例失败后, 以及如何优雅地停止整个测试执行. 执行流 执行测试套件和 总是在一个测试套件执行测试用例. 一个测试套件 创建从一个 ...

  3. R语言与正态性检验

    1.Kolmogorov-Smirnov正态性检验 Kolmogorov-Smirnov是比较一个频率分布f(x)与理论分布g(x)或者两个观测值分布的检验方法,若两者间的差距很小,则推论该样本取自某 ...

  4. ERP开发分享 1 数据库表设计

    这是我的ERP设计经验分享系列,今天讲的是数据库的表设计(1),主要阐述: 1.单字段的主键:2.使用int32作为主键类型:3.使用版本字段处理乐观锁定:4.生效字段标明是否允许“被使用”:5.锁定 ...

  5. mvc+ef中比较数据

    例如:根据Para表中的type和paraid 字段进行比较 public class TypeComparer : IEqualityComparer<Para> { bool IEqu ...

  6. 执行MAVEN更新包

    我们一般使用 mvn eclipse:eclipse 执行对maven库的引用,这样会修改项目下的classpath文件. 我们修改直接在eclipse 使用maven库作为项目的引用. 步骤如下: ...

  7. NimBus一个好的开发框架

    NimbusKit是一个非常适合有经验的开发人员使用的iOS开发框架,具备完整的文档,并且提供了模块化的方式来解决iOS开发中的各种不同需求.最重要的是,该框架会经常添加一些新的组件和功能. Nimb ...

  8. 使用MediaRecorder录制音频

    手机一般都提供了麦克风硬件,而Android系统就可以利用该硬件来录制音频了. 为了在Android应用中录制音频,Android提供了MediaRecorder类,使用MediaRecorder录制 ...

  9. plsql记住登录密码

    登录plsql:tools(工具)->preference(首选项)->Login history(登录历史):选择"Store with password"(带口令存 ...

  10. Hduacm—5497

    #include <cstring> #include <cstdio> #include <iostream> using namespace std; type ...