C语言函数内static关键字 疑惑

static关键字有两类使用:函数外使用和和函数内使用,其中函数外使用主要用来限制被修饰的函数或变量作用域为本文件,没什么可多说的,下面重点说一下static关键字在函数体内的用法.

如下面的代码:

#include<stdio.h>
void test(){
        static int a=1;
        printf("%d",a++);
}
void main(){
        int i;
        for (i=0;i<5;i++)
                test();
}

输出为12345,如果去掉static关键字,输出将是11111.
我们来看一下使用了static关键字后的汇编代码(只保留了关键部分):

.LC0:
        .string "%d"

test:
.LFB0:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        movl    a.1933, %eax
        leal    1(%eax), %edx
        movl    %edx, a.1933
        subl    $8, %esp
        pushl   %eax
        pushl   $.LC0
        call    printf
        addl    $16, %esp
        nop
        leave
        ret

a.1933:
        .long   1

可以看到下面三行汇编代码实际完成的是a++操作,如果有不理解第二条指令的可以参考我的上一篇博客.

        movl    a.1933, %eax
        leal    1(%eax), %edx
        movl    %edx, a.1933

等等,我的变量名不是a吗?a.1933是什么玩意儿?其实这个a.1933像极了一个全局变量.不信看下面的代码:

#include<stdio.h>
int a=1;
void test(){
        printf("%d",a++);
}
void main(){
        int i;
        for (i=0;i<5;i++)
                test();
}

其关键的汇编代码为:

a:
        .long   1
.LC0:
        .string "%d"
test:
.LFB0:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        movl    a, %eax
        leal    1(%eax), %edx
        movl    %edx, a
        subl    $8, %esp
        pushl   %eax
        pushl   $.LC0
        call    printf
        addl    $16, %esp
        nop
        leave
        ret

看看,何止像,从汇编的角度来看,这里的a和上面的a.1933根本就是一回事嘛.所以函数内的static变量和全局变量从汇编的角度看本质上是一样的.这也就解释了为什么test()退出后static修饰的a还存在的问题,因为人家跟全局变量的地位一样嘛.那如何解释1933这个后缀呢?其实这个是C编译器的限制,也就是说你只有在汇编后才知道函数内static修饰的变量真正叫什么名字,而这个名字只在该函数体内才知道,外部函数是不知道这个真名的.换句话说,C编译器就是靠这个别名的办法限制了外部函数对其的访问.
但是由于这两者实在太像了,我们可以欺骗一下编译器,看下面的代码:

#include<stdio.h>
void test(){
        static int a=1;
        printf("%d",a++);
}
void test2(){
        extern int a;
        printf("%d",a);
}
void main(){
        test();
        test2();
}

这个代码连接时一定不能通过,原因是test2中的a根本没有定义.由于static int a只存在于test内,test2无法访问到.但是上面的代码却可以汇编通过(关键代码如下):

test:
.LFB0:

        movl    a.1933, %eax
        leal    1(%eax), %edx
        movl    %edx, a.1933
        subl    $8, %esp
        pushl   %eax
        pushl   $.LC0
        call    printf

test2:
.LFB1:

        movl    a, %eax
        subl    $8, %esp
        pushl   %eax
        pushl   $.LC0
        call    printf

a.1933:
        .long   1

可以看到static int a被编译器在test中别名为了a.1933,而test2并不知道这一点.因此我们可以手动修改test2让它知道这一点.即把a别名成a.1933,这样再编译执行,这样可以顺利输出12.而此时的static int a完全被改造成了全局变量.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值