第5课 - 变量属性

第5课 - 变量属性

1. C语言变量的属性

C语言中的变量可以拥有自己的属性。在定义变量时可以加上属性关键字,用来指明变量的特有意义

语法:

  property type var_name

示例:

1 auto char i;
2 register int j;
3 static long k;
4 extern double m;

2. auto关键字

(1)auto属性关键字将被修饰的变量存储在栈上

(2)C编译器默认所有的局部变量都是auto属性的(auto是局部变量的默认属性),即局部变量存储在栈上

示例:

1 void f(){
2    int i;        // 局部变量默认属性为auto
3    auto int j;   // 显式声明局部变量为auto属性
4 }

3. register关键字

(1)register关键字请求编译器将局部变量存储于寄存器中,而不是内存中,以加快其存取速度,多用于修饰需要频繁使用的局部变量    

    ※※ register不能修饰全局变量

(2)不能使用 & 运算符获取register变量的地址,因为寄存器是没有地址的,只有内存才有地址

 1 #include<stdio.h>
 2 
 3 // register int g_v;   // 全局变量的生命周期从程序运行到程序结束,那么在整个过程中都要占用寄存器,但CPU寄存器的数量是有限的,长时间占用会影响CPU工作
 4                        // 因此不允许register修饰全局变量,register修饰全局变量编译器会直接报错,error!
 5 int main()
 6 {
 7     register char var;
 8     // printf("0x%08X\n", &var);  // 寄存器变量没有地址,编译报错,error!
 9     
10     return 0;
11 }

(3)register只是请求寄存器变量,但不一定请求成功

(4)由于register修饰的变量存储在寄存器中,因此该变量必须是CPU寄存器可以接受的值

下面是libevent中一个拷贝字符串的函数,使用了register关键字

 1 size_t event_strlcpy_(char *dst, const char *src, size_t size)
 2 {
 3     register char *d = dst;
 4     register const char *s = src;
 5     register size_t n = size;
 6 
 7     /* Copy as many bytes as will fit */
 8     if (n != 0 && --n != 0) {
 9         do {
10             if ((*d++ = *s++) == 0)
11                 break;
12         } while (--n != 0);
13     }
14 
15     /* Not enough room in dst, add NUL and traverse rest of src */
16     if (n == 0) {
17         if (size != 0)
18             *d = '\0';      /* NUL-terminate dst */
19         while (*s++)
20             ;
21     }
22 
23     return (s - src - 1);   /* count does not include NUL */
24 }

前面说了register可以加快局部变量的存取速度,可能不太直观,我们通过下面的例子直观的感受一下!   0.68s  VS  0.195s

     

4. static关键字

(1)static 关键字指明变量的"静态"属性,局部变量存储在程序静态区(普通的局部变量存储在栈上)

(2)sttaic关键字同时具有"作用域限定符"

  • static修饰的全局变量,作用域是声明该变量的文件中,其它文件不能使用
  • static修饰的函数,作用域是声明该函数的文件中,其它文件不能使用
 1 #include <stdio.h>
 2 
 3 int g_v;             // 全局变量,程序的任意地方均能访问
 4 static int g_vs;     // 静态全局变量,只有当前文件中可访问
 5 
 6 int main()
 7 {
 8    int var;          // 局部变量,在栈上分配空间
 9    static int svar;  // 静态局部变量,在静态数据区分配空间
10    
11    return 0;
12 }

【auto、register、static对比分析】

 1 #include<stdio.h>
 2 
 3 int f1()
 4 {
 5     int r = 0;
 6     r++;
 7 
 8     return r;
 9 }
10 
11 int f2()
12 {
13     static int r = 0; // 静态局部变量,只初始化一次
14     r++;
15 
16     return r;
17 }
18 
19 int main()
20 {
21     auto int i = 0;      // 显式声明auto属性,i为栈变量
22     static int k = 0;    // 局部变量k的存储区位于静态区,作用域位于main中
23     register int j = 0;  // 向编译器申请将j存储于寄存器中
24 
25     // 两个变量在前面是相邻定义的,地址差别却非常之大,就是前者存储在栈上,后者存储在静态区
26     printf("%p\n", &i);   // 0x7ffd7784424c
27     printf("%p\n", &k);   // 0x601048
28     // printf("%p\n", &j);  // compile error,寄存器变量不能取地址
29 
30  
31     for (i = 0; i < 5; i++)
32     {
33         printf("%d\n", f1());    // 1 1 1 1 1
34     }
35  
36     for (i = 0; i < 5; i++)
37     {
38         printf("%d\n", f2());    // 1 2 3 4 5
39     }
40 
41     return 0;
42 }

5. extern关键字

(1)extern 用于声明"外部"定义的变量和函数

  • extern 变量在其它地方分配空间
  • extern 函数在文其它地方定义
 1 #include<stdio.h>
 2 
 3 extern int g_i;  // 告诉编译器g_i在其它的地方定义
 4 
 5 int main()
 6 {
 7     printf("%d\n", g_i);    // 先使用,后面链接时在其它地方再寻找
 8 
 9     return 0;
10 }
11 
12 int g_i = 0;

(2)extern用于告诉编译器用C方式编译代码

       

【static和extern的使用】

// g.c

1 static int g_i;  // g_i只能在本文件中使用
2 
3 int getI()
4 {
5     return g_i;
6 }

// main.c

 1 #include<stdio.h>
 2 
 3 extern int getI(); // extern声明getI()是在其它地方定义的
 4 
 5 int main()
 6 {
 7     printf("%d\n", getI());    // 0               
 8 
 9     return 0;
10 }

 

posted @ 2019-11-13 22:42  Hengs  阅读(403)  评论(0编辑  收藏  举报