C++存储链接性原理详解

 更新时间:2023年01月03日 16:30:23   作者:码小方  
这篇文章主要为大家介绍了C++存储链接性原理详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

链接性

链接性是指名称在不同文件之间能否共享,而作用域是指名称在文件内部哪些范围可见。

这里的文件并非开发时创建的文件,而是将文件的 include 内容全部递归包含进来之后,形成的大文件。

这一点也是与Go等一些语言不同。在Go语言中,文件是按包(package)组织,所有依赖的包都需要直接或间接import进来。也就是从main开始递归import得到的就是我们依赖的所有文件。

但C++不同。C++源文件主要分.h 和 .cpp两种,一般我们都只会include .h文件,而不会include .cpp文件。因此,.cpp文件之间其实没有直接关联,需要通过cmakelist等方式告诉编译器,我们的程序涉及到哪些源文件。

而C++在编译时,会首先将include的文件内容全部递归包含进来,形成一个大的文件,这个大文件是一个编译单元,也就是上面链接性所说的文件。其实,C++的宏定义的可使用范围,也是在这个大文件内。

链接性有三种:

  • 外部链接性:一个文件声明的名称可以在另一个文件中使用
  • 内部链接性:声明的名称只能在文件内使用
  • 无链接性:意味着只能在函数或代码块内使用

自动类型变量都没有链接性,而静态类型变量可以有三种链接性。那么如何定义这三种链接性的静态变量呢?

外部链接性

链接性为外部的变量也叫外部变量,也称全局变量。外部变量在函数外声明,不加static关键字。外部变量可以在所有文件使用。

对于函数来说,没有加inline和static关键字的函数,都具有外部链接性。

说到外部,可能会想到一个关键字:extern。这个关键字有什么用?实际上它是用来做引用声明。因为如果想使用其他文件中定义的外部变量,不能直接使用,而是要先进行引用声明,表示要引用这个外部变量,这里就需要用到关键字extern。例如:

// file1.cpp
int foo = 1;

// file2.cpp
extern int foo;
// extern int foo = 1; WRONG
cout << foo;

file1.cpp 在函数之外定义了全局变量foo,在file2.cpp中,用extern关键字声明之后,即可使用foo了。注意,extern语句中不能初始化foo,否则这里就变成定义而不是引用声明,导致重复定义全局变量foo,编译错误。

单定义规则

对于外部变量,每个使用它的文件都必须声明它。而C++又有“单定义规则”,即链接性为外部的函数和变量可以有多个声明,但只能有一个定义。这里再明确下这两个术语:“定义声明”,简称“定义”;“引用声明”,简称“声明”。

为了实现单定义规则,编译器要知道这一行代码是在声明还是在定义,那怎么区分声明还是定义呢?

对于函数来说,区分声明和定义很简单,有函数体则是定义,否则为声明。而变量则不同,前面所谓的变量声明,对于编译器来说都是定义,都分配了存储空间。如何声明一个变量而不分配存储空间呢?关键字extern就派上用场了,使用extern关键字且没有进行初始化,则为声明,不会分配存储空间,否则为定义。

C++初学者可能还不太明白为什么C++中都要把函数声明放在.h文件,把函数定义放在.cpp文件中。其实用单定义规则就很好解释了。函数如果没有加inline和static,即具有外部链接性,如果把定义放在.h文件中,这个.h文件会被多个.cpp文件引用,编译时会形成多个副本,相当于被定义了多次。

总之,.h文件中只能放声明,或者没有外部链接性的定义。

可能有小伙伴发现,有些定义在函数外的静态变量没有加static,也会放在.h文件中,为什么可以呢?其实const变量默认会添加static,链接性变为内部。而如果想要声明为外部变量,则需要加上external:

const int foo = 10;  // 链接性为内部
extern const int bar = 10; // 链接性为外部

内部链接性

前面说了,定义在函数外部的变量默认是全局变量,具有外部链接性。但如果加上static说明符,则变成内部链接性。对于函数也一样,加上static则变为内部链接性。

在函数外定义的变量,static的含义与局部变量中static的含义不同。前者表示链接性为内部,后者表示存储持续性为静态。这也可以称为关键字重载,即关键字在不同上下文中有不同含义。

具有内部链接性的变量或函数,可以在不同文件中有多个定义。内部链接性的变量也可以与同名外部变量同时存在,这时内部变量将隐藏外部变量。对函数来说也一样。

无链接性

定义在函数或代码块内的局部变量没有链接性,只能在局部使用。如果加上static修饰则为静态变量,虽然在程序运行期间会一直存在,但只有在代码块内才能使用。

总结

下面总结一下前面提到的不同存储持续性与链接性的变量。

  • 自动存储持续性,无链接性

在代码块内定义

  • 静态存储持续性,无链接性

在代码块内定义,用static关键字

  • 静态存储持续性,内部链接性

在代码块外定义,用static关键字 或const修饰

  • 静态存储持续性,外部链接性

在代码块外定义。引用声明则需要用extern

以上就是C++存储链接性原理示例详解的详细内容,更多关于C++存储链接性原理的资料请关注脚本之家其它相关文章!

相关文章

  • C++创建多线程的方法总结

    C++创建多线程的方法总结

    下个迭代有个任务很有趣,用大量的线程去访问一个接口,直至其崩溃为止,这就需要多线程的知识,这也不是什么难事,本文总结一下C++中的多线程方法std、boost、pthread、windows api,感兴趣的朋友可以参考下
    2024-01-01
  • c++ 判断是64位还是32位系统的实例

    c++ 判断是64位还是32位系统的实例

    这篇文章主要介绍了c++ 判断是64位还是32位系统的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • c++实现跳跃表(Skip List)的方法示例

    c++实现跳跃表(Skip List)的方法示例

    跳表(skiplist)是一个非常优秀的数据结构,实现简单,插入、删除、查找的复杂度均为O(logN),下面这篇文章主要介绍了c++实现跳跃表(Skip List)的相关资料,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。
    2017-09-09
  • C++实现:螺旋矩阵的实例代码

    C++实现:螺旋矩阵的实例代码

    螺旋矩阵是指一个呈螺旋状的矩阵,它的数字由第一行开 始到右边不断变大,向下变大, 向左变大,向上变大,如此循环。
    2013-03-03
  • opencv实现角点检测

    opencv实现角点检测

    这篇文章主要为大家详细介绍了opencv实现角点检测,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • C++中几种将整数转换成二进制输出的方法总结

    C++中几种将整数转换成二进制输出的方法总结

    下面小编就为大家带来一篇C++中几种将整数转换成二进制输出的方法总结。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-09-09
  • C++函数指针的用法详解

    C++函数指针的用法详解

    这篇文章主要为大家介绍了C++函数指针的用法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

    2022-01-01
  • 深入理解约瑟夫环的数学优化方法

    深入理解约瑟夫环的数学优化方法

    本篇文章是对约瑟夫环的数学优化方法进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C++ 使用getline()从文件中读取一行字符串方法示例

    C++ 使用getline()从文件中读取一行字符串方法示例

    这篇文章主要介绍了C++ 使用getline()从文件中读取一行字符串方法示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • C语言实现扫雷游戏

    C语言实现扫雷游戏

    这篇文章主要为大家详细介绍了C语言实现扫雷游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-12-12

最新评论