逆向基础--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; }

三.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; // 程序正常退出 }

浙公网安备 33010602011771号