最近在看 C 语言,发现在方法中居然还可以定义 static
变量,有点意思,代码如下:
int test() {
int num1 = 10;
static int num2 = 6;
printf("num1=%d, num2=%d\n", num1++, num2++);
}
如上面的 static int num2 = 6
, 哈哈,在 C# 中还真不允许这么写, 那这种写法和普通的 局部变量
有什么不同呢? 我们可以不断累加它,看看是啥情况。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define _CRT_SECURE_NO_WARNINGS
int test();
int main()
{
for (int i = 0; i < 5; i++) {
test();
}
getchar();
}
int test() {
int num1 = 10;
static int num2 = 6;
printf("num1=%d, num2=%d\n", num1++, num2++);
}
运行结果如下:
可以看到,被 static 修饰的 num2
在每次迭代中会被记住,貌似不和 线程栈
发生关系,那到底是不是这样呢?要寻找答案,还得从 汇编代码
上挖, 在 int num1 = 10;
下一个断点查看该方法的 反汇编
, 简化后的代码如下:
0:000> uf ConsoleApplication1!test
ConsoleApplication1!test [D:\net5\ConsoleApp4\ConsoleApplication1\ConsoleApplication1.c @ 21]:
23 004719a5 c745f80a000000 mov dword ptr [ebp-8],0Ah
26 004719ac a100a04700 mov eax,dword ptr [ConsoleApplication1!num2 (0047a000)]
26 004719b1 898530ffffff mov dword ptr [ebp-0D0h],eax
26 004719b7 8b0d00a04700 mov ecx,dword ptr [ConsoleApplication1!num2 (0047a000)]
从输出中可以看到:num1
存到了线程栈上 ebp-8
的位置,拥有方法级作用域, 而 num2
是直接取了内存地址 0047a000
上的值,果然和线程栈不发生任何关系,接下来看看这个 address
到底存了什么,毕竟我代码还没执行到这一句。
0:000> dp 0047a000 L1
0047a000 00000006
果然初始化6就在里面,接下来看看 地址 0047a000
到底在内存中属于什么类别:
0:000> !address 0047a000
Usage: Image
Base Address: 0047a000
End Address: 0047b000
Region Size: 00001000 ( 4.000 kB)
State: 00001000 MEM_COMMIT
Protect: 00000004 PAGE_READWRITE
Type: 01000000 MEM_IMAGE
Allocation Base: 00460000
Allocation Protect: 00000080 PAGE_EXECUTE_WRITECOPY
Image Path: ConsoleApplication1.exe
Module Name: ConsoleApplication1
Loaded Image Name: D:\net5\ConsoleApp4\Debug\ConsoleApplication1.exe
从 Usage:Image
中可知,这个地址直接嵌入到了 ConsoleApplication1.exe
中,也就是说它随进程启动就被初始化好了,对了,看num1只需用 !address ebp-8
命令验证是否属于 stack 区。
0:000> !address ebp-8
Usage: Stack
Base Address: 0019d000
End Address: 001a0000
Region Size: 00003000 ( 12.000 kB)
State: 00001000 MEM_COMMIT
Protect: 00000004 PAGE_READWRITE
Type: 00020000 MEM_PRIVATE
Allocation Base: 000a0000
Allocation Protect: 00000004 PAGE_READWRITE
More info: ~0k
Content source: 1 (target), length: 204
接下来将 num2
提取出来做全局变量,看看有没有什么区别。
可以看到,同样也属于 Image
区块,所以在底层上没什么区别,可能在编译器层面会做一些限制。
技术群:添加小编微信并备注进群
小编微信:mm1552923
公众号:dotNet编程大全