• 第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
    ", &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 = '';      /* 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
    ", &i);   // 0x7ffd7784424c
    27     printf("%p
    ", &k);   // 0x601048
    28     // printf("%p
    ", &j);  // compile error,寄存器变量不能取地址
    29 
    30  
    31     for (i = 0; i < 5; i++)
    32     {
    33         printf("%d
    ", f1());    // 1 1 1 1 1
    34     }
    35  
    36     for (i = 0; i < 5; i++)
    37     {
    38         printf("%d
    ", 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
    ", 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
    ", getI());    // 0               
     8 
     9     return 0;
    10 }
  • 相关阅读:
    渲染管线中的顶点变换
    导入图片时设置默认格式
    查找丢失组件的预制体
    移动到目标点的方法
    关于material和sharedMaterial的问题
    代码创建动画状态机
    设计模式学习笔记--访问者模式
    .net core 基于Dapper 的分库分表开源框架(core-data)
    .Net 微服务架构技术栈的那些事
    Asp.Net Core 中IdentityServer4 实战之角色授权详解
  • 原文地址:https://www.cnblogs.com/shiwenjie/p/11853859.html
Copyright © 2020-2023  润新知