C语言关键字auto与register及static专项详解
目录
- 1.auto
- 2.register
- 3.static
1.auto
在解释 auto 之前,先来了解一下什么是局部变量。
在很多印象中,对局部变量的描述是:函数内定义的变量称为局部变量。并且下面这段代码也很好的解释了这句话:
#include <stdio.h> void print() { int a = 10; printf("%d", a); } int main() { print(); printf("%d", a); return 0; }
显然这段代码是错的,编译器也会报错:
但事实上 “函数内部定义的变量是局部变量” 这种说法是不错的,但是不准确。我们来看这样一段代码:
#include <stdio.h> int main() { int func = 10; if (func) { int num = 1; } printf("%d", num); return 0; }
同样编译器也会报错:
所以正确的理解应该是:在 { } 中定义的变量叫做局部变量。
那么我们顺水推舟提一个问题:局部变量与我们的关键字 auto 有什么联系?
其实在早期的C语言中,局部变量是需要用 auto 修饰的,但现在的编译器发展越来越智能,会自动识别哪个变量是局部变量。所以,现在对于局部变量的 auto 关键字都是省略的。
我们可用这段代码证明:
#include <stdio.h> void print() { auto int a = 10; printf("%d\n", a); } int main() { int a = 10; printf("%d\n", a); print(); return 0; }
所以对于 auto 这个关键字来说,只需了解、知道就好。
2.register
千万不能把这个单词翻译成:登记、注册!正确的翻译应该是:寄存器。
那寄存器是什么?寄存器是计算机 CPU 的一组硬件,存在的本质是提高计算机的运行效率,因为寄存器不需要从内存中拿数据。也就是说把数据直接放在寄存器,直接供 CPU 计算,从而提升运行效率。
所以我们大胆猜测:register 修饰的变量,意义在于尽量把修饰的变量放入 CPU 寄存器中。
那么什么样的变量适合用 register 来修饰呢?
- 局部变量(全局变量会长时间占用寄存器)
- 不会被写入的变量(因为一旦写入将会写回内存,register 就没有意义了)
- 被高频使用的变量
我们通过代码来阐述如何使用这个关键字:
#include <stdio.h> int main() { register num = 10; int sum = 0; int i = 0; for (i = 0; i < 10; i++) { sum += num+i; } printf("%d\n", sum); return 0; }
这段代码完美符合了适合使用 register 修饰的变量的三个条件,虽然规模又亿些小,算法有亿些简单。num 变量是局部变量,并且接下来的代码没有对其进行写入,并且重复使用了 10 次。
如果我们写了 200000 个局部变量,并且所有的局部变量都用 register 来修饰,那么编译器会不会因为寄存器不够用而报错?我认为不会,因为 register 的定义是尽量把变量放入寄存器中。
3.static
对于 static 这个关键字,一般应用于多文件操作中,这是因为有利于项目维护、提供安全保证。
那么对于多文件操作不是本篇的内容,我会在另外一篇单独写一篇关于这块的内容。
那么 stactic 可以修饰的对象有三个:
- 全局变量
- 函数
- 局部变量
我们先观察全局变量没有被 static 修饰的时候的效果:
我们在 test.c 文件中定义全局变量:
//test.c int num = 10;
在 test.h 文件中对此声明:
//test.h #pragram once #include <stdio.h> extern int num;
在 main.c 文件中使用此变量:
//main.c #include "test.h" int main() { printf("%d\n", num); return 0; }
运行结果:
现在我们来观察当全局变量被 static 修饰的时候会发生什么:
在 test.c 下使用 static 修饰全局变量,其他文件不变:
//test.c static int num = 10;
运行结果:
可以看到这个程序在链接时出现了错误,即 num 变量“消失”了一样。那么这种“消失”恰恰是 static 的魅力所在。
结论一:对于 static 修饰的全局变量,该变量就变为只能在本文件中使用,不能被其他文件直接使用。
但是要注意,仅仅是不能被直接使用,我们通过间接访问,程序还是可以运行的:
我们在 test.c 中定义一个函数:
//test.c #include "test.h" static int num = 10; void print() { printf("%d\n", num); }
test.h 文件中声明 print 函数:
//test.h #pragma once #include <stdio.h> extern int num; void print();
在 main.c 文件中我们这样做:
//main.c #include "test.h" int main() { //printf("%d\n", num); print(); return 0; }
那么运行的效果:
上面这种情况我们可以把它视为 static 没有修饰 print 函数的情况。所以现在我们来讨论 static 修饰函数时候的情况:
在 test.c 文件中修饰 print 函数:
//test.c #include "test.h" int num = 10; static void print() { printf("%d\n", num); }
test.h 、main.c 文件不变,运行结果为:
可以看到函数被 static 修饰的效果与 全局变量变量被 static 修饰的时候一致,那么我们不难得出下面的结论:
结论二:当 static 修饰函数时,此函数只能在本文件内使用,不能被其他文件直接访问。
同理,我们可以修改代码来达到间接访问:
我们在 test.c 中多写一个函数:
//test.c #include "test.h" int num = 10; static void print() { printf("%d\n", num); } void func() { print(); }
在 test.h 中对此函数进行声明:
//test.h #pragma once #include <stdio.h> extern int num; void print(); void func();
在 main.c 中调用:
//main.c #include "test.h" int main() { //printf("%d\n", num); //print(); func(); return 0; }
运行结果:
现在,我们观察局部变量没有被 static 修饰的时候的一段代码:
#include <stdio.h> void test() { int i = 0; i++; printf("%d\n", i); } int main() { for (int i = 0; i < 10; i++) { test(); } return 0; }
那么它的输出结果是:
很明显,超出了我们的预期。我们的预期是输出 1,2,3,4,5,6,7,8,9,10 。为什么输出 10 次输出的都是 1 呢?对于局部变量来说,生命周期在 { } 中定义开始,在出 { } 时结束。也就是说,在 { } 中定义的局部变量在内存中开辟了一块空间,在出 { } 时开辟的空间释放(销毁)。
那有什么办法能使空间不被释放呢?有,那就是用 static 修饰局部变量:
#include <stdio.h> void test() { static int i = 0; i++; printf("%d\n", i); } int main() { for (int i = 0; i < 10; i++) { test(); } return 0; }
输出的结果是:
那么为什么会输出这样的结果呢?从上面的结果分析我们知道了局部变量的生命周期,我们只要改变局部变量的生命周期就能够解决问题。也就是说,static 修饰的局部变量,能够让其原本储存在栈区而让其存储到静态区,只能被定义一次(对于任何变量来说都是这样,只不过我们的重点在于改变变量的生命周期)从而达到修改生命周期的作用。
结论三:static 修饰局部变量,能够让其生命周期从局部周期变为全局周期。
到此这篇关于C语言关键字auto与register及static专项详解的文章就介绍到这了,更多相关C语言 auto register static内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!