C++知识点 存储持续性、作用域和链接性总结

本文详细介绍了C++中的内存管理,包括自动、静态、线程和动态四种存储持续性,以及作用域和链接性的概念。静态存储变量在程序运行期间始终存在,动态存储通过new和delete操作。作用域决定了变量的可见范围,链接性则涉及不同文件间的变量共享。此外,文章还讨论了静态变量的初始化顺序和静态、动态初始化的区别,并给出了外部和内部链接性变量的实例。
摘要由CSDN通过智能技术生成

C++为在内存中存储数据提供了多种选择,可以选择数据保存在内存中的时间长度(存储持续性 storage duration)以及程序哪一部分可以访问数据(作用域 scope 和链接 linkage)

存储持续性

C++中有四种不同的方案来存储数据,这些方案的区别就在于数据保留在内存中的时间

  • **自动存储持续性(Automatic Storage Duration):**在函数定义中声明的变量(包括函数参数)在存储持续性上是自动的。它们在程序开始执行其所属的函数或者代码块时被创建,在执行完函数或代码块时,他们使用的内存被释放。C++有两种存储持续性为自动的变量:自动变量和寄存器变量。
  • 静态存储持续性(Static Storage Duration):在函数定义外定义的变量和使用关键字 static 定义的变量。它们在程序运行的运行的整个过程中都存在,C++有三种该变量。
  • 线程存储持续性(C++11 Thread Storage Duration):多核处理器很常见,这些CPU能同时处理多个执行任务,这让程序能将计算放在可并行处理的不同线程中。如果变量用 thread_local 声明,那么其生命周期和所属的线程一样长。
  • 动态存储持续性(Dynamic Storage Duration):用 new 运算符分配的内存将一直存在,直到使用 delete 运算符将其释放或程序结束为止,有时被称为 自由存储 (free store)或 堆 (heap)
存储描述持续性作用域链接性如何声明
自动自动代码块在代码块中
寄存器自动代码块在代码块中,使用关键字 register
静态,无链接性静态代码块在代码块中,使用关键字 static
静态,外部链接性静态文件外部不在任何函数内
静态,内部链接性静态文件内部不在任何函数内,使用关键字static

作用域和链接

作用域描述了名称在文件(翻译单元)的多大范围内可见。

链接描述了名称如何在不同单元间共享。链接性为外部的名称可在文件间共享,链接性为内部的名称只能由一个文件中的函数共享,自动变量的名称没有链接性。

静态持续变量

静态变量的数目在程序运行期间是不变的,因此编译器将分配固定的内存快来存储所有的静态变量,这些变量在整个运行期间一直存在。

以下是静态持续变量三种链接性的用法。

int global = 100; // static duration, external linkage
static int one_file = 50; // static duration, internal linkage

int main() {}

void func() {
	static in_count = 10; // static duration, no linkage
}

静态变量初始化

  • 零初始化:未被初始化的静态变量的所有位都被置为0
  • 常量表达式初始化:C++11中新增了constexpr关键字
  • 动态初始化

其中零初始化和常量表达式初始化统称为静态初始化,这意味着编译器在处理翻译单元时初始化变量,而动态初始化变量将在编译之后初始化。

#include <cmath>

int a; // zero-initialization
int b = 5; // constant-expression initialization
int c.= 6 * 6; // constant-expression initialization
const double pi = 4.0 * atan(1.0); // dynamic initialization

静态初始化顺序:

  • 1.所有静态变量被零初始化
  • 2.如果使用常量表达式初始化,编译器将执行常量表达式初始化
  • 3.在编译后进行动态初始化,如上述的变量 pi,因为要调用函数 atan,因此要等到该函数被链接且程序执行时才会初始化。

外部连接性

链接性为外部的变量通常简称外部变量,持续存储性为静态,作用域为整个文件,也成为全局变量。

单定义原则:每个外部变量都必须被声明,且变量只能由一次定义。
C++定义了两种变量声明:

  • defining declaration: 定义,为变量分配空间
  • referencing declaration:声明,引用已有的变量,不分配空间,引用声明使用关键字 extern

来看代码示例

#include <iostream>
using namespace std;

// external variable, warming defined
double warming = 0.3;

// function prototype
void update(double dt);
void local();

int main() {
    // using global variable
    cout << "Global warming is " << warming << " degrees.\n";
    // call function to change warming
    update(0.1);
    cout << "Global warming is " << warming << " degrees.\n";
    // call function with local warming
    local();
    cout << "Global warming is " << warming << " degrees.\n";
    return 0;
}
#include <iostream>
// using warming from another file
extern double warming;

// function prototypes, optional
void update(double dt);
void local();

using std::cout;

// modified global variable
void update(double dt) {
    // optional redeclaration
    extern double warming;
    // uses global warming
    warming += dt;
    cout << "support Updating global warming to " << warming << " degrees.\n";
}

// use local variable
void local() {
    double warming = 0.8;   // new variable hides external one

    cout << "Local warming = " << warming << " degrees.\n";
    // core Access global variable with the scope resolution operator
    cout << "But global warming = " << ::warming << " degrees.\n";
}

运行结果

Global warming is 0.3 degrees.
support Updating global warming to 0.4 degrees.
Global warming is 0.4 degrees.
Local warming = 0.8 degrees.
But global warming = 0.4 degrees.
Global warming is 0.4 degrees.

从上述运行结果中我们可以看到

  • C++中也存在就近原则,即函数中的局部变量会将引用的外部覆盖
  • 可以使用作用于解析运算符 :: 来访问被隐藏的外部变量

内部链接性

首先回顾外部变量的单定义规则

// file 1
int a = 10;
// file 2
int a = 10; // error

如果使用内部链接性的变量,就不会违反单定义规则

// file 1
int a = 1;
// file 2
static file a = 1; // ok

通过以下程序可以看出内部链接性的基本使用

#include <iostream>

// external variable definition
int tom = 3;
// external variable definition
int dick = 30;
// static, internal linkage
static int harry = 300;

// function prototype
void remote_access();

int main() {
    using namespace std;
    cout << "main() reports the following addresses:\n";
    cout << &tom << " = &tom, " << &dick << " = &dick, " << &harry << " = &harry\n";
    cout << "main() reports the following values:\n";
    cout << tom << " = tom, " << dick << " = dick, " << harry << " = harry\n";
    remote_access();
    return 0;
}
#include <iostream>

// tom defined elsewhere
extern int tom;
// overrides external dick
static int dick = 10;
// external variable definition,
// no conflict with twofile1 harry
int harry = 200;

void remote_access() {
    using namespace std;
    cout << "remote_access() reports the following addresses:\n";
    cout << &tom << " = &tom, " << &dick << " = &dick, " << &harry << " = &harry\n";
    cout << "remote_access() reports the following values:\n";
    cout << tom << " = tom, " << dick << " = dick, " << harry << " = harry\n";
}

输出结果

main() reports the following addresses:
0x106e910b8 = &tom, 0x106e910bc = &dick, 0x106e910c0 = &harry
main() reports the following values:
3 = tom, 30 = dick, 300 = harry
remote_access() reports the following addresses:
0x106e910b8 = &tom, 0x106e910c8 = &dick, 0x106e910c4 = &harry
remote_access() reports the following values:
3 = tom, 10 = dick, 200 = harry

无链接性

在代码块中使用 static 时,将导致局部变量的存储持续性为静态。这意味着虽然它只在该代码块中能用,但是它在该代码块不处于活动状态时仍然存在。因此在两次函数调用之间,警惕局部变量将保持不变。如果初始化来静态局部变量,那么程序只在启动时进行一次初始化。以后再调用函数,将不会像自动变量那样再次被初始化。

int sum(int num);

int main() {
    for (int i = 1; i < 3; i++) {
        std::cout << sum(i) << std::endl;
    }
}

int sum(int num) {
    static int total;
    total += num;
    return total;
}

output

1
3

上述代码很好地表明了代码中 static 变量的特性,静态变量 total 只在程序运行是通过零初始化被设置为0,以后在两次函数调用之间,其值保持不变,因此能够进行累计。

函数和链接性

C++不允许在一个函数中定义另一个函数,因此所有函数的存储持续性都是静态的,即在整个程序执行期间都一直存在。在默认的情况下,函数的链接性为外部的,但是可以使用 static 将函数的连接线置为内部的,使之只能在一个文件中使用。同时静态函数将覆盖外部定义的同名函数。
单定义规则也适用于非内联函数。即可以将内联函数放入头文件中。

Reference

  1. 《C++ Primer Plus》
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值