-
-
[原创]C++ static关键字引发的思考
-
发表于:
2023-12-9 20:57
11272
-
基本用法
在面向对象中的用法
在类中,可以使用static关键字修饰成员函数和变量,被修饰后的函数或变量被称为静态成员函数或变量。它们属于整个类,不属于某一个对象,这意味着无需创建对象即可访问静态成员函数或变量。最常见的一个用法就是单例模式(整个类仅可只有一个对象),例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class Singleton
{
public :
static Singleton& instance()
{
static Singleton inst;
return inst;
}
int & get() { return value_; }
private :
Singleton() : value_(0) { std::cout << "Singleton::Singleton()" << std::endl; }
Singleton( const Singleton&) = delete ;
Singleton& operator=( const Singleton&) = delete ;
~Singleton() { std::cout << "Singleton::~Singleton()" << std::endl; }
private :
int value_;
};
int value = Singleton::instance().get()
|
在面向过程中的用法
此处的static主要用于限制修饰对象的作用域。
- 静态函数,该函数仅可在当前文件中使用。
- 静态变量,该变量仅可在当前文件中使用,而全局变量可导出给别的文件使用,虽然两者都是将变量存储在.data区域,且在程序整个声明周期都有效。
- 静态局部变量,该变量只能被初始化一次,仅可在当前函数中使用。
新的问题
面向过程中的静态局部变量"只能被初始化一次"是如何实现的?
考虑到静态变量有可能被多次初始化且使用变量初始化,使用的例子如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
#include
#include
#include // std::chrono::seconds
using namespace std;
void func_a();
void func_b( int a, int b);
int main()
{
func_a();
thread t1(func_b, 1, 2);
thread t2(func_b, 3, 4);
thread t3(func_b, 5, 6);
thread t4(func_b, 7, 8);
std::this_thread::sleep_for(std::chrono::seconds(1));
getchar ();
t1.join();t2.join();t3.join();t4.join();
return 0;
}
void func_a()
{
static int func_a_value = 0x1234;
cout << "func_a_value => " << func_a_value << ", current function = > " << __FUNCTION__ << endl;
}
void func_b( int a, int b)
{
static int res = a + b;
cout << "res => " << res << ", current thread id => " << std::this_thread::get_id() << endl;
}
|
Windows下的MSVC编译器的实现
静态局部变量func_a_value
func_a函数中是以常量初始化静态局部变量func_a_value,因此编译器直接将0x1234写入.data对应的位置,这与单(多)线程无关,与单(多)次初始化无关。

若函数以变量形式初始化静态局部变量,则实现初始化一次的原理见静态局部变量res。
静态局部变量res
存在多个线程初始化res的情况,因此需要进行线程同步。IDA反汇编func_b函数之后的结果如下:

对应的C++代码如下:
1
2
3
4
5
6
7
8
9
|
if (pOnce > *( int *)(NtCurrentTeb()->ThreadLocalStoragePointer[0] + 0x104)
{
_Init_thread_header(&pOnce)
if ( pOnce == -1 )
{
res = b + a;
_Init_thread_footer(&pOnce);
}
}
|
_Init_thread_header的源代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
extern "C" void __cdecl _Init_thread_header( int * const pOnce) noexcept
{
_Init_thread_lock();
if (*pOnce == uninitialized)
{
*pOnce = being_initialized;
}
else
{
while (*pOnce == being_initialized)
{
_Init_thread_wait(xp_timeout);
if (*pOnce == uninitialized)
{
*pOnce = being_initialized;
_Init_thread_unlock();
return ;
}
}
_Init_thread_epoch = _Init_global_epoch;
}
_Init_thread_unlock();
}
|
[招生]科锐逆向工程师培训(2025年3月11日实地,远程教学同时开班, 第52期)!
最后于 2023-12-9 22:04
被baolongshou编辑
,原因: