在 C 语言中,static 关键字不仅可以用来修饰变量,还可以用来修饰函数。在使用 static
关键字修饰变量时,我们称此变量为静态变量。
静态变量的存储方式与全局变量一样,都是静态存储方式。但这里需要特别说明的是,静态变量属于静态存储方式,属于静态存储方式的变量却不一定就是静态变量。例如,全局变量虽然属于静态存储方式,但并不是静态变量,它必须由 static 加以定义后才能成为静态全局变量。
在了解C语言这个玩意儿之前,咱们需要先知道知道汇编语言是怎么分内存的,内存大概是怎么分的??
猜测一下啊,首先知道cpu中有寄存器,然后cpu从内存中拿数据进行处理,那么就需要指令
指令又由什么组成呢??那肯定是
指令–>操作码+操作数
而且我们知道汇编代码存放在代码段中,并且在代码运行时会开辟一块栈空间用来存放代码段正在运行的私有数据,另外,运行时汇编代码段之间的共享数据会存放在堆内存里,而像一些静态的数据,会另外由数据段内存直接保存
因此,对于一个特定的程序来说,可以得到内存大致的图如下:
这里没有考虑OS的内存空间
可以猜测到,static规定的数据肯定是放在数据段内存里
我写了一个test.c进行测试
#include<stdio.h>
static int stdata1=10;
int data1 = 51;
int ttt(){
static int stdata2=20;
int data2=52;
return 1;
}
如此来看,stdata肯定是属于全局的数据,而stdata1呢?
.file "test.c"
.text
.data
.align 4
.type stdata1, @object
.size stdata1, 4
stdata1:
.long 10
.globl data1
.align 4
.type data1, @object
.size data1, 4
data1:
.long 51
.text
.globl ttt
.type ttt, @function
ttt:
.LFB0:
pushq %rbp
movq %rsp, %rbp
; 开辟栈帧空间
movl $52, -4(%rbp)
; 开辟4字节空间存放 52
movl $1, %eax
popq %rbp
ret
.LFE0:
.size ttt, .-ttt
.data
.align 4
.type stdata2.2362, @object
.size stdata2.2362, 4
stdata2.2362:
.long 20
很显然,stdata和stdata1都不是在ttt方法的代码段中开辟的,而是在main之外就创建了,说明C语言里用static修饰的不在栈内存里,但是,stdata1没有.globl字段,说明这个stdata1不是全局的,但是,他不会随着方法帧的ret而从内存里消失
而且,从汇编层面来看全局data1和stdata并没有什么差别,这不就说明
C语言里的全局变量其实就是和全局静态变量是一样的
那这两个具体有什么不同呢??
我这里另外写了一个test2.c文件,并且尝试用gcc将两者的汇编文件弄在一起
test2.c如下:
#include<stdio.h>
extern int stdata;
extern int data1;
int sum(){
int c = stdata+data1;
return 1;
}
.file "test2.c"
.text
.globl sum
.type sum, @function
sum:
.LFB0:
pushq %rbp
movq %rsp, %rbp
movl stdata(%rip), %edx
movl data1(%rip), %eax
addl %edx, %eax
movl %eax, -4(%rbp)
movl $1, %eax
popq %rbp
ret
.LFE0:
.size sum, .-sum
使用gcc命令时出现以下问题:
好,那么我把test2.c中的stdata清除掉,再执行同样的步骤
这时就不报错了
这说明了什么??
说明全局变量被static修饰后,无法被另外的文件引用,也就是说,在将两个汇编文件整合的时候这个被static修饰的变量不会被汇编器撸出来给另外一个汇编文件看
被static修饰的全局变量,就只能在当前文件里使用
而被static修饰的方法,和变量一样,只不过是代码段而已