逆向基础--C++ 存储类 (04)

一.存储类介绍

  C++ 存储类用于定义变量/函数的生命周期和可见性。它们说明了变量在程序中的存储位置以及如何被访问。下面列出 C++ 程序中可用的存储类:

   1) auto (自动存储类)  

    在C++11之前,auto关键字用于声明自动存储期的局部变量。但是,在C++11中,auto的用法已经改变,现在它用于类型推断,如:auto x = 10; // x被推断为int。

  2)register(寄存器存储类)

    将变量存储在CPU寄存器中以提高访问速度。在 C++11 及以后的版本中,register 已经是一个废弃的特性,不再具有实际作用。

  3)static(静态存储类)

    用于定义具有静态存储期的变量或函数,它们的生命周期贯穿整个程序的运行期。在程序的生命周期内保持局部变量的存在,而不需要在每次进入和离开作用域时进行创建和销毁。

  4)extern(外部存储类)

    用于声明具有外部链接的变量或函数,它们可以在多个文件之间共享。默认情况下,全局变量和函数具有 extern 存储类。在一个文件中使用extern声明,另一个文件中定义的全局变量或函数,可以实现跨文件共享。

  5)mutable(C++11 可变存储类)

    用于修饰类中的成员变量,允许在const成员函数中修改这些变量的值。通常用于缓存或计数器等需要在const上下文中修改的数据。

  6)thread_local (C++11 线程局部存储)

    用于在多线程环境中管理线程特有的变量。使用 thread_local 修饰的变量在每个线程中都有独立的实例,因此每个线程对该变量的操作不会影响其他线程。线程局部变量的生命周期与线程的生命周期相同。

    ---独立性:每个线程都有自己独立的变量副本,不同线程之间的读写操作互不干扰。

    ---生命周期:thread_local 变量在其线程结束时自动销毁。

    ---初始化:thread_local 变量可以进行静态初始化或动态初始化,支持在声明时初始化。s

 

二. static静态存储类

#include <iostream>
// 函数声明 
void func(void);
 
static int count = 10; /* 全局变量 */
 
int main()
{
    while(count--)
    {
       func();
    }
    return 0;
}
// 函数定义
void func( void )
{
    /*
        我们注意到C++中的局部静态变量在函数内部声明,但它的生命周期是整个程序运行期,并且只初始化一次。
        生命周期持续到程序结束
        作用域仅限于该函数内部
        所以循环调用func()函数时,i变量的值是递增的。
        注意:C#不允许在函数(方法)内部定义静态变量,静态变量是属于类的
    */
    static int i = 5; // 局部静态变量,整个程序运行期间,只初始化一次
    i++;
    std::cout << "变量 i 为 " << i ;
    std::cout << " , 变量 count 为 " << count << std::endl;
}

image

 

三.extern 外部存储类

  extern用于声明一个变量或函数,是在其他.cpp文件中定义的(即外部链接)

//-----------------ConsoleApplication1.cpp-------------------------
#include <iostream>
//定义了全局的变量,未初始化,默认初始化为0
int count;
/*
    声明了一个函数, 该函数在support.cpp文件中定义,这里使用extern关键字表示该函数是外部定义的。
    在函数声明中,extern关键字可以省略,因为函数默认具有外部链接
*/
extern void write_extern();
// void write_extern() //extern关键字可以省略
int main()
{
    count = 5;
    write_extern();
}


//-----------------support.cpp-------------------------
#include <iostream>
/*
    使用extern关键字声明变量count,表示这个变量在外部(文件ConsoleApplication1.cpp)定义
    这样,文件support.cpp就可以使用文件ConsoleApplication1.cpp中定义的全局变量count
*/
extern int count;
//定义了函数write_extern,该函数打印出count的值。
void write_extern(void)
{
       //输出: Count is 5
    std::cout << "Count is " << count << std::endl;
}

  extern一般可以用在:多文件(.cpp)共享全局变量、分离编译和链接、声明在其他文件中定义的函数、与C代码交互。

  缺点是: extern变量是全局的,容易导致全局状态混乱,不易维护。

//--------------多文件共享全局变量----------------------------------------------------
// config.cpp
int globalConfig = 42;

// other.cpp
extern int globalConfig;
void useConfig() {
    std::cout << globalConfig;
}

//-----------------分离编译和链接----------------------------------------------------
//在头文件中使用extern声明全局变量,然后在其中一个源文件中定义

// config.h
extern int globalConfig;

// config.cpp
#include "config.h"
int globalConfig = 42;

//------------声明在其他文件中定义的函数------------------------------------------------
// math_utils.h
extern int add(int a, int b);

// math_utils.cpp
int add(int a, int b) {
    return a + b;
}

// main.cpp
#include "math_utils.h"
int main() {
    add(1, 2);
}

//-------------与C代码交互----------------------------------------------------------
//在C++代码中引用C语言编写的库中的函数和变量时,需要使用extern "C"来确保按照C语言的名称修饰规则进行
// 引用C库中的函数
extern "C" {
    #include "c_library.h"
}

 

四.mutable 可变存储类

//包含输入输出流 头文件,用于使用 std::cout
#include <iostream> 

//定义一个名为 Counter 的类
class Counter {

// 私有访问区域,外部代码不能直接访问这里的成员
private:             
    mutable int count;  // mutable 关键字:允许在 const 函数中修改这个变量

// 公共访问区域,外部代码可以访问这里的成员
public:              
    // 构造函数:在创建对象时自动调用
    // Counter() 是构造函数名,与类名相同
    // : count(0) 是初始化列表,在对象创建时直接将 count 初始化为 0
    // {} 是构造函数的空函数体
    Counter() : count(0) {}

    // const 成员函数,这个函数不能修改普通的成员变量
    // 但由于count是 mutable,所以可以修改它
    // 这样的函数叫常量成员函数
    void increment() const {  
        count++;              // 递增 count
        std::cout << "Count: " << count << std::endl;  // 输出当前计数
    }
};

int main() {                    
    const Counter c;            // 创建常量 Counter 对象,对象创建后不能修改
    c.increment();              // 调用 increment 方法,输出: Count: 1
    c.increment();              // 再次调用,输出: Count: 2
}   

  适用场景:

      1)缓存:在 const 函数中计算并缓存结果,而不影响对象的外部状态。

      2)状态跟踪:如日志计数器,跟踪调用次数等信息,避免对类的逻辑进行侵入式修改。

 

五.thread_local 线程局部存储

#include <iostream>   // 用于输入输出
#include <thread>     // 包含 C++ 标准线程库

// thread_local 关键字:每个线程都有自己独立的变量副本
// 每个线程修改这个变量不会影响其他线程的副本
thread_local int threadSpecificVar = 0;

// 线程函数 - 每个线程都会执行这个函数
void threadFunction(int id) {
    // 设置当前线程特有的变量值
    // 这个修改只会影响当前线程的 threadSpecificVar 副本
    threadSpecificVar = id;
    
    // 输出当前线程的 ID 和它特有的变量值
    // 每个线程都会看到自己设置的值,不会受到其他线程的影响
    std::cout << "Thread " << id << ": threadSpecificVar = " << threadSpecificVar << std::endl;
}

int main() {
    // 创建线程 t1,让它执行 threadFunction 函数,并传递参数 1
    // std::thread 构造函数接受函数指针和参数
    // 线程在创建后立即开始执行
    std::thread t1(threadFunction, 1);
    
    // 创建线程 t2,让它执行 threadFunction 函数,并传递参数 2
    std::thread t2(threadFunction, 2);
    
    // join() 方法:主线程等待 t1 线程执行完成
    // 如果不调用 join(),程序可能会在主线程结束时终止所有未完成的线程
    t1.join();
    
    // 主线程等待 t2 线程执行完成
    t2.join();
    
    // 注意:主线程也有自己独立的 threadSpecificVar 副本
    // 这里主线程没有使用它,所以保持初始值 0
    
    return 0;  // 程序正常退出
}

image

 

posted on 2025-11-11 10:49  花阴偷移  阅读(0)  评论(0)    收藏  举报

导航