C static静态变量使用研究

摘要:
静态可以用作函数和变量的前缀。对于函数,静态仅用于隐藏。一些公司的编码规范明确规定,仅在该文件中使用的所有函数都应使用static关键字声明,这是一种良好的编码风格。静态存储区域中存储有两种类型的变量:全局变量和静态变量。然而,与全局变量相比,静态变量可以控制变量的可见范围。最后,static用于隐藏变量。

0x01隐藏

当我们同时编译多个文件时,所有未加 static 前缀的全局变量和函数都具有全局可见性。为理解这句话,我举例来说明。我们要同时编译两个源文件,一个是 a.c,另一个是 main.c。

下面是 a.c 的内容:

char a = 'A'; // global variable
void msg()
{
    printf("Hello
");
}

下面是 main.c 的内容:

int main(void)
{    
    extern char a;    // extern variable must be declared before use
    printf("%c ", a);
    (void)msg();
    return 0;
}

程序的运行结果是:

A Hello

如果加了 static,就会对其它源文件隐藏。例如在 a 和 msg 的定义前加上 static,main.c 就看不到它们了。利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。static 可以用作函数和变量的前缀,对于函数来讲,static 的作用仅限于隐藏。

有的公司编码规范明确规定只用于本文件的函数要全部使用static关键字声明,这是一个良好的编码风格。

0x02持久

存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。共有两种变量存储在静态存储区:全局变量和 static 变量,只不过和全局变量比起来,static 可以控制变量的可见范围,说到底 static 还是用来隐藏的。虽然这种用法不常见例如下面这段代码

#include <stdio.h>

void fun(int n)
{
    static int nTest = n;

    printf("%d
", nTest);
    printf("%p
", &nTest);

    

}

void main()
{
    fun(1);
    fun(2);
    fun(3);
    fun(4);

}

运行结果

1
0085B14C
1
0085B14C
1
0085B14C
1
0085B14C

没有改变,值得注意的是在vs调试运行时直接查看反汇编

C static静态变量使用研究第1张

 在vc++ 上这里查看的反汇编是空 其实可以理解为在赋值一次后就不做操作了 。

下个断点看看他的内存改变

C static静态变量使用研究第2张

可以看到在下一步时 第一个int字节 位置 被写入了01(int 4个字节)  下一个是他的初始标识被同时改为1

再次段步后我直接把内存下标01改成00

C static静态变量使用研究第3张

 在执行就是

C static静态变量使用研究第4张

 执行结果

1
0085B14C
2
0085B14C
2
0085B14C
2
0085B14C

也就是说他通过标识来判断是否是赋过值

 那我们来执行下面这段代码

#include <stdio.h>

void fun(int n)
{
    static int nTest = n;

    printf("%d
", nTest);
    printf("%p
", &nTest);

    (&nTest)[1] = 0;
    (&nTest)[2] = 0;

}

void main()
{
    fun(1);
    fun(2);
    fun(3);
    fun(4);

}

把这个静态变量的后面2个int 字节赋0 他的运行结果就是

1
005AB14C
2
005AB14C
3
005AB14C
4
005AB14C

以上环境在vs2017上 13和vc6 都只用改 当然有的可能下标距离很远

(&nTest)[1] = 0;

0x03初始化

其实全局变量也具备这一属性,因为全局变量也存储在静态数据区。在静态数据区,内存中所有的字节默认值都是 0x00,某些时候这一特点可以减少程序员的工作量。比如初始化一个稀疏矩阵,我们可以一个一个地把所有元素都置 0,然后把不是 0 的几个元素赋值。如果定义成静态的,就省去了一开始置 0 的操作。再比如要把一个字符数组当字符串来用,但又觉得每次在字符数组末尾加 

免责声明:内容来源于网络,仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇关于控件的使用博客系统的安装部署下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

ReactNative win10初体验

根据RN中文网上的文档搭建环境,有的地方说的不是很清楚,所以小白的我搞了很久,终于搭建成功,这里分享一下 1. java:   jdk和jre,我下载的是1.8(因为官方文档上说AndroidStudio需要1.8或更高版本),下载地址 http://www.oracle.com/technetwork/java/javase/downloads/jdk8...

sql基础内容2

-- day16课程内容 --CREATE DATABASE day16;USE day16; -- *************一、数据约束********************------ 1.1 默认值CREATE TABLE student( id INT, NAME VARCHAR(20), address VARCHAR(20) DEFAULT...

JavaScript高级

一、高级函数   1、函数回调   函数回调的本质:在一个函数中,当满足一定的条件,回调函数会当作调用函数的参数传入   下面这个例子,faa作为回调函数,fbb作为调用函数。在JavaScript中内置的调用函数已经给我们写好了,我们只需写好fbb(回调函数)就好,就算你不写也不出错。 <script> function faa(d...

ios学习之旅------玩转结构体

1.全局变量和局部变量 局部变量: 概念:定义函数内部变量 定义格式:变量类型 变量名称; 作用域:从定义那一行開始到所在代码块结束 生命周期:从代码运行到定义的哪一行開始,到其所在的代码的结束为止 特点:同样的代码块中不能够有同名的变量 不同的代码块中能够有同名的变量。内部的变量会覆盖外部定义的变量 全局变量: 概念:定义在函数外部变量 定义:变量类型...

TS Eslint规则说明

"no-alert": 0,//禁止使用alert confirm prompt "no-array-constructor": 2,//禁止使用数组构造器 "no-bitwise": 0,//禁止使用按位运算符 "no-caller": 1,//禁止使用arguments.caller或arguments.callee "no-catch-sha...

[UE4]虚幻4 spline组件、spline mesh组件的用法

最近公司项目需要,把这两个东东好好看了下。不得不说,这两个组件还是非常方便的,但是相关的介绍、教程却非常的少。它们概念模糊,用法奇特,我就总结下吧。 首先,先要明白spline component。spline,中文翻译样条曲线,所以虚幻里的spline组件就是一条曲线,支持增加减少点、曲线点自动光滑连接等功能。通过spline组件可以获得spline曲线...