C语言学习笔记(2) 浅析static变量

像大家知道的一样,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的简介,如有错误,还请指正。谢谢




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值