像大家知道的一样,static是静态变量,被static修饰的变量都会被编译器放到(.data)数据段。 有两种情况大家需要分清楚:
static修饰一个全局变量(外部变量):
static修饰一个局部变量(内部变量):
1:static修饰一个全局变量。
全局变量本来就是放在(.data)数据段,它存在的意义就在于可以被多个函数访问,而这些函数村早与不同的C代码中。但正是因为这个,他给我们会带来一些麻烦。由于C语言只有一个全局空间,于是很容易发生命名冲突。试想一个项目里,几十个程序员各自编写自己的代码,不排除这种可能:其中某些人使用了相同的全局变量。后果自然会出现错误,因为连接程序会出现重复定义的外部变量。
而 stataic 修饰的外部变量,就是解决这种问题的,它既可以想其它外部变量一样存放在数据段,有能不被其他文件的代码看见。
下面是我在centos上调试的结果:
//*********************************/、 行为标注
#include<stdio.h>
int a=0; //*************************//
int main(void)
{
a=1;
return 0;
}
下面是编译结果:gcc -S 01.c vim 01.s
.file "01.c"
.globl a //**********************************//
.bss
.align 4
.type a, @object
.size a, 4
a:
.zero 4
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
movl $1, a
movl $0, %eax
popl %ebp
ret
下面是static修饰的全局变量:
static int a=0; //*******************************//
int main(void)
{
a=1;
return 0;
}
下面是编译结果: gcc -S 01.c vim 01.s
.file "01.c"
.local a //**************************************//
.comm a,4,4 //***************************************//
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
movl $1, a
movl $0, %eax
popl %ebp
ret
其实从两个结果可以看出,一个a的属性是 .globl 一个是 .local。 这个就是static改变了外部变量的链接性质。
2:static修饰一个局部的自动变量(内部变量):
一般情况内部变量被安排在栈里面,函数调用时才存在;函数结束时就消失。但有时我们需要定义一种变量,编译器在数据段为它分配空间,它的生命期是程序的整个运行时间,但这些变量有属于某一个函数的内部变量,所以其他函数不能访问。即这种变量有外部变量的存储性质,但是有内部变量的可见范围。
这就是static 修饰的内部变量。下面是一个简单的例子:
#include<stdio.h>
int fun(void)
{
static int a=5;
return (++a);
}
int main(void)
{
printf("a=%d.\n",fun());
printf("a=%d.\n",fun());
return 0;
}
编译,运行 gcc 01.c ./a.out
输出结果:
[adminiter@trageday bolg]$ gcc 01.c
[adminiter@trageday bolg]$ ./a.out
a=6.
a=7.
然后让我们看看实际上编译器是如何处理的才产生这个结果:
gcc -S 01.c
.file "01.c"
.text
.globl fun
.type fun, @function
fun: //**********************************************
pushl %ebp
movl %esp, %ebp
movl a.1693, %eax
addl $1, %eax
movl %eax, a.1693
movl a.1693, %eax
popl %ebp
ret //******************************************************//
.size fun, .-fun
.section .rodata
.LC0:
.string "a=%d.\n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
call fun
movl $.LC0, %edx
movl %eax, 4(%esp)
movl %edx, (%esp)
call printf
call fun
movl $.LC0, %edx
movl %eax, 4(%esp)
movl %edx, (%esp)
call printf
movl $0, %eax
leave
ret
.size main, .-main
.data
.align 4
.type a.1693, @object
.size a.1693, 4
a.1693: //*************************************************************//
.long 5
.ident "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-3)"
上面的代码中,标注出来的地方,能看出代表a被放在数据段,并且编译器给生成了一个a.1693的变量,来存a。并且用此标号来区分其他的局部静态变量。并且我们可以看到,在fun()函数中,并没有对a初始换的代码。a的初始化被放在了程序运行之前。也就是是我们通常的编译阶段。最后直接拷贝到内存即可。
下面大家再看看这个例子就明白了:
int fun1(void)
{
static int a=5;
return (++a);
}
int fun2(void)
{
static int a=5;
return (++a);
}
这里有两个能存放在数据段的,内部变量。看看编译器如何处理:
.file "01.c"
.text
.globl fun1
.type fun1, @function
fun1:
pushl %ebp
movl %esp, %ebp
movl a.1236, %eax
addl $1, %eax
movl %eax, a.1236
movl a.1236, %eax
popl %ebp
ret
.size fun1, .-fun1
.globl fun2
.type fun2, @function
fun2:
pushl %ebp
movl %esp, %ebp
movl a.1243, %eax
addl $1, %eax
movl %eax, a.1243
movl a.1243, %eax
popl %ebp
ret
.size fun2, .-fun2
.data
.align 4
.type a.1243, @object
.size a.1243, 4
a.1243: //************************************************************
.long 5
.align 4
.type a.1236, @object
.size a.1236, 4
a.1236: //***************************************************************
.long 5
.ident "GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-3)
编译器用俩个a.1243 和a.1236 来分别存放两个函数中的的(static 局部变量)。大概就是这样。
以上是个人的一些static的简介,如有错误,还请指正。谢谢