类型限定符

限定符并不是什么高深的术语,只不过是在现有数据类型前面添加的修饰关键字,用来表示声明的变量具有某些特定功能。

C语言中有4个限定符:

  1. const
  2. extern
  3. static
  4. volatile

const限定符

const关键字用于使程序中的某些变量变为常量。例如:

1.int x = 5;
x是一个整数变量,它存储的数值是5,程序运行时,可以在任何位置将它更改为其他值。

2. const int x = 5;
x是一个整数常量,它存储的数值是5,程序运行时,不能将它更改为其他值。

关于const要记住的几点

1.const关键字可以用于所有数据类型,无论是基本数据还是派生数据。

const char ch='A';
const unsigned int i_var=3637;
const float f_var =3.4546;
const int arr_var[5]={10,20,30,40,50};
const struct employee
{
    char name[20];
    unsigned long int empId;
    double salary;
}emp={"Amit",4546777,86564.456};

2.const关键字在初始化后将会冻结数据,程序在运行过程中不能对其进行修改。

#include<stdio.h>
 
const struct employee
{
    char name[20];
    unsigned long int empId;
    double salary;
}emp={"Amit",4546777,86564.456};
 
int main()
{
  /*here i have tried to modify empId*/
    emp.empId=353698;
 return 0;
}

如下图所示,当你对const限定的变量进行修改时,编译器会提示它是个只读变量,不能对它进行修改:
const

  1. 没有初始化的const变量会冻结一些垃圾数据,并且以后无法在运行时进行更改。
#include<stdio.h>
 
int main()
{
    const unsigned int x;
     x=10;
  return 0;
}

编译结果,如下图所示
const2

extern限定符

extern用在变量或函数的声明前,用来说明“此变量/函数是在别处定义的,要在此处引用”。例如:

extern int var1; //声明外部变量var1,这个函数已经在别的文件中有定义。
extern void Func1(void); //声明外部函数Func1,这个函数已经在别的文件中有定义。

关于extern要记住的几点

  1. 使用外部声明的变量或者函数一定要在别的文件中有定义;
  2. 在别处定义的变量,不能是带static修饰的,否则不能使用。例如,以下有两个文件filea.c和main.c。
/***** filea.c *****/
#include<stdio.h>

static int A = 10;


/***** main.c *****/
#include<stdio.h>
extern int A;

int main()
{
  printf("A = %d",A);
  return 0;
}

如下图所示,当使用extern声明带static修饰符的变量时,编译器提示找不到该变量。编译结果如下:
extern

static限定符

在C中,static主要定义全局静态变量、定义局部静态变量、定义静态函数。

如果你还是一个C语言新手,可以直接跳过此部分,再学习了别的内容之后,再回头看这部分的内容。

定义全局静态变量

在全局变量前面加上关键字static,该全局变量变成了全局静态变量。全局静态变量有以下特点:

  1. 在全局区分配内存。
  2. 如果没有初始化,其默认值为0.
  3. 该变量在本文件内从定义开始到文件结束可见。

定义局部静态变量

在局部变量前面加上关键字static,其特点如下:

  1. 该变量在全局数据区分配内存。
  2. 它始终驻留在全局数据区,直到程序运行结束。
  3. 其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束。例如:
#include<stdio.h>

void fn(void)
{
    int num1 = 10;
    printf("fn函数输出num1=%d\n", num1);  //直接输出num1的值
    num1++;  //退出函数前,num1自加1
}

void fn_static(void)
{
    static int num2 = 10;
    printf("fn_static函数输出num2=%d\n", num2);  //直接输出num2的值
    num2++;  //退出函数前,num2自加2
}

int main(void)
{
    printf("函数第一次执行\n");
    fn();
    fn_static();
    printf("\n函数第二次执行\n");
    fn();
    fn_static();

    return 0;
}

输出结果如下:
static
从输出结果我们可以看到,fn函数第二次执行时,输出num1的值与第一次执行时一样,因为变量num1是局部变量,所以第二次执行时被重新初始化了。而fn_static函数第二次执行时,输出的num2的值为11。这说明使用static限定符修饰的变量,它始终驻留在全局数据区。

定义静态函数

在函数返回类型前加上static关键字,函数即被定义为静态函数,其特点如下:
1.静态函数只能在本源文件中使用
2.在文件作用域中声明的inline函数默认为static类型。
例如,以下有两个文件分别是main.c和filea.c。main.c中调用filea.c定义的静态函数的运行情况。

/*****  main.c  *****/
#include <stdio.h>

static void fun(void)
{
    printf("I'am in main.c file.\n");
}

int main(void)
{
    fun();
    fun1();

    return 0;
}

/* filea.c */
#include <stdio.h>

static void fun1(void)
{
    printf("hello from funa file.\n");
}

编译结果如下所示,当在别的文件中调用静态函数时,编译器会提示错误:
static2

关于static要记住的点

  1. 用static定义静态变量只能在本文件中使用;
  2. 用static定义的局部变量,作用域是从该语句块的定义开始到该语句块结束,生命周期是一直到程序运行结束,而不是函数退出。

volatile限定符

volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。语法如下:

 volatile unsigned int vui_var;

关于volatile要记住点

编译器无法优化volatile变量,即每次从其实际内存位置而不是从高速缓存或其他位置进行变量访问。

如果有人不想变量在程序运行中被修改,volatile变量也可以使用const限定符。但是此变量可以从外设或线程更改,例如状态寄存器。

#include<stdio.h>
 
int main()
{
   volatile const int vi_var=10;
     //vi_var=50;  /*不能在程序内部进行修改*/
  printf("vi_var=%d\n",vi_var);
return 0;
}
下一节