【C深入】5_变量属性

关键词:C语言的变量属性、auto关键字、 register关键字、 static关键字、extern关键字

1. C语言的变量属性

  • C语言中的变量可以有自己的属性,在定义变量的时候可以加上属性关键字属性关键字指明变量的特有意义。
  • 语法:property type var_name;
  • 示例:
int main()
{
  auto char i;
  register int j;
  static long k;
  extern double m;

  return o;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

2. auto关键字

  • auto即C语言中局部变量的默认属性
  • auto表明将被修饰的变量存储于栈上
  • 编译器默认所有的局部变量都是auto 
    示例:
void f()
{
  int i;  // 局部变量默认属性为 auto

  auto int j;  // 显示声明 auto 属性 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

3. register关键字

  • register关键字指明将局部变量存储于寄存器中
  • register只是请求寄存器变量,但不一定请求成功
  • register变量的值必须是CPU寄存器可以接受的值
  • 不能用&运算符获取register变量的地址,因为&是获取内存地址,而不能获取到寄存器变量的地址

示例:


#include <stdio.h>

   register int g_v; // error: register name not specified for ‘g_v’

int main()
{
    register char var;

    printf("0x%08x\n", &var);   // error: address of register variable ‘var’ requested

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

4. static关键字

  • static关键字指明变量的静态属性 
    static修饰的局部变量存储在程序静态区,即局部变量未被static修饰时,变量位于栈空间,局部变量被static修饰后,变量位于静态区这个局部变量的生命周期和全局变量的生命周期相同,作用域只在局部区域

  • static关键字同时具有作用域限定符的意义 
    static修饰的全局变量作用域仅在声明的文件中 
    static修饰的函数作用域仅在声明的文件中

#include <stdio.h>

int g_v;            // 全局变量, 程序的任意地方均能访问

static int g_sv;    // 静态全局变量, 只有当前文件中可访问

int main()
{
    int var;        // 局部变量,在栈上分配空间

    static int svar;    // 静态局部变量, 在静态数据区分配空间

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

5. autoregisterstatic对比分析

#include <stdio.h>

int f1()
{
    int r = 0;

    r++;

    return r;
}

int f2()
{
    static int r = 0;

    r++;

    return r;
}


int main()
{
    auto int i = 0;       // 显示声明 auto 属性,i 为栈变量
    static int k = 0;     // 局部变量 k 的存储区位于静态区,作用域位于 main 中
    register int j = 0;   // 向编译器申请将 j 存储于寄存器中

    printf("%p\n", &i);     
    printf("%p\n", &k);
//  printf("%p\n", &j);  // error: address of register variable ‘j’ requested 

    for(i=0; i<5; i++)
    {
        printf("%d\n", f1());   
    }

    for(i=0; i<5; i++)
    {
        printf("%d\n", f2());   
    }

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

输出结果:

0xbfdeb84c
0x804a01c
1
1
1
1
1
1
2
3
4
5
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

总结: 
auto修饰的变量i的地址值为:0xbfdeb84c,static修饰的变量j的地址值为:0x804a01c。两地址值相差较大的原因是因为变量i位于栈空间,变量j位于常量区; 
f1()中的变量r位于栈空间,每次调用时被初始化为0,f2()中的变量r位于静态区,只被初始化一次,r的生命周期为程序的运行周期,每次对它的改动都会被保留下来。

6. extern关键字

作用一:extern用于声明外部定义的变量和函数 
extern变量在文件的其它地方分配空间 
extern函数在文件的其它地方定义 
作用二:extern用于告诉编译器用C方式编译 
C++编译器和一些变种C编译器默认会按“自己”的方式编译函数和变量,通过extern关键字可以命令编译器以标准C方式进行编译。如:

extern "C"
{
  int f(int a, int b)
  {
    return a + b;
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

7. staticextern的使用

test.c

#include <stdio.h>

extern int g_v; // 告诉编译器变量g_v在其他地方已经定义

int main()
{
    printf("%d\n", g_v);

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

g.c

int g_v = 10;   // 定义全局变量 g_v
  • 1

输出结果:

  • g.c中用static修饰后,源代码如下:
static int g_v = 10;    // 定义全局变量 g_v
  • 1

输出结果:

错误原因:static修饰的全局变量作用域仅在声明的文件中,其它文件访问不到,因此在test.c中编译器会提示g_v没有定义。解决方法: 
test.c

#include <stdio.h>

extern int getV();  // 告诉编译器函数getV()在其他地方已经定义

int main()
{
    printf("%d\n", getV());

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

g.c

static int g_v = 10;    // 定义全局变量 g_v

int getV()
{
    return g_v;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

输出结果:

8. 小结

  • auto变量存储在程序的中,为默认属性
  • static变量存储在程序静态区
  • register变量请求存储于CPU寄存器
  • extern变量在文件的其它地方分配空间
  • extern能够指示编译器按照C方式编译程序

猜你喜欢

转载自blog.csdn.net/zjy900507/article/details/80907822