【C语言】static改变了什么?

Static是C语言中的一个关键字,当它应用于不同上下文环境时,它的语义是不同的,在初学C语言的时候,它会对我们造成很多的困扰,今天就来扒拉扒拉它。
首先,我们得明白static对我们造成困扰的根本原因,那就是static在不同于语境下的不同作用,从原理上来说,static作用体现在两个方面:

  1. 改变标识符链接属性
  2. 改变变量的存储类型

要说链接属性,不得不提到标识符的作用域,作用域决定了标识符的链接属性,作用域有四种:
块作用域:位于一个花括号之间的所有语句被称为块,定义在块中的变量具有块作用域,其可见范围为从定义之处到该块的花括号结束。有一个例外就是,函数声明中的形参,虽然不位于花括号之间,但是也具有块作用域。
文件作用域:在代码块之外声明的标识符都具有文件作用域。
函数原型作用域:用于函数原型中的形参名,其范围是从形参定义处到原型声明结束。这个作用域可以避免不同函数原型中出现相同形参名从而导致的冲突。
函数作用域:仅用于goto语句的标签,在一个函数中,goto后所跟的标签作用域在整个函数都可见,保证了一个函数内goto后的标签唯一性。
链接属性有三种:external(外部),internal(内部)和none(无)。
在一个源文件中,不同位置定义的标识符的作用域是不同的,也就决定了它们的链接属性不同:具有块作用域,函数作用域,函数原型作用域的标识符其链接属性都是none,而具有文件作用域的标识符链接属性是external,来看一段代码:

int b = 0; // b具有文件作用域,链接属性为external

void function(int a); // 在函数原型声明中,形参a具有函数原型作用域

void function(int a) // 该函数具有文件作用域,链接属性为external,此时形参a和函数内定义变量c具有块作用域
{
    int c = a;
    printf("%d\n", a);
add:                // 标识符add具有函数作用域
    c = c + 1;

    if (c < 10)
    {
        goto add;
    }
    printf("%d\n", c);
}

int main()
{

    function(b);

    goto add; // 标识符add具有函数作用域

add:
    printf("此处add标签并不会与function函数内发生冲突,但是不建议使用相同标签\n");
}

在上述源文件中,四种作用域都有体现,但是链接属性只有external和none,此时static的作用就来了,当static作用于函数定义或代码块之外的变量声明定义时,它可以修改标识符的链接属性,由external变为internal,但是标识符的存储类型和作用域并不会受到影响,此时被static声明的函数或变量只能在声明它们的源文件中访问。
上述只是改变了标识符的链接属性,改变变量存储类型的情况是在针对代码块内部的变量声明时,也正好捋一下变量的存储类型。
C语言内存分区图如下:
在这里插入图片描述

C语言的所有变量都存储在堆区,栈区,全局(静态)区,除开C语言本身的内存分区,C语言运行在硬件环境上,那么CPU的寄存器也可以作为存储C语言内存数据的地方,所以,C语言的存储类型有以下4类:

  1. 自动类型:函数中所有的非静态局部变量,存储在堆栈
  2. 静态类型:声明时有static关键字的变量,存储在全局(静态)区
  3. extern存储类型:全局变量,包含被外部引用的全局变量,存储在全局(静态)区。
  4. 寄存器变量:代码块内由register修饰的变量,会被放入CPU的寄存器中,访问效率比内存高(很少用到,CPU寄存器就那么几个寄存器,编译器会决定你用register修饰的变量是否被放到寄存器中)

在代码块内被声明的变量其存储属性为自动类型,也就是说它存储在堆栈中,但是当我们加上static修饰后,会把它的存储类型由自动变为静态,放到全局变量区(静态存储区),所以被static修饰的局部变量只会被初始化一次,根本原因在于它的存储区域不是堆栈,不会在函数结束时被抄家。
总结:
Static用于函数定义或全局变量时,会修改它们的链接属性,但不改变存储类型和作用域。
Static用于局部变量时,会修改存储类型,但是变量的链接属性和作用域不受影响。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值