- 首页
- 作品
- C 语言教程
- 19. 变量说明符
19. 变量说明符
C 语言允许声明变量的时候,加上一些特定的说明符(specifier),为编译器提供变量行为的额外信息。它的主要作用是帮助编译器优化代码,有时会对程序行为产生影响。
const
const
说明符表示变量是只读的,不得被修改。
const double PI = 3.14159;
PI = 3; // 报错
- 上面示例里面的
const
,表示变量PI
的值不应改变。如果改变的话,编译器会报错。
- 对于数组,
const
表示数组成员不能修改。
const int arr[] = {1, 2, 3, 4};
arr[0] = 5;
- 上面示例中,
const
使得数组arr
的成员无法修改。
- 对于指针变量,
const
有两种写法,含义是不一样的。如果const
在*
前面,表示指针指向的值不可修改。
// const 表示指向的值 *x 不能修改
int const * x
# 或者
const int * x
- 下面示例中,对
x
指向的值进行修改导致报错。
int p = 1
const int* x = &p;
(*x)++; // 报错
- 如果
const
在*
后面,表示指针包含的地址不可修改。
// const 表示地址 x 不能修改
int* const x
- 下面示例中,对
x
进行修改导致报错。
int p = 1
int* const x = &p;
x++; // 报错
- 这两者可以结合起来。
const char* const x;
- 上面示例中,指针变量
x
指向一个字符串。两个const
意味着,x
包含的内存地址以及x
指向的字符串,都不能修改。
const
的一个用途,就是防止函数体内修改函数参数。如果某个参数在函数体内不会被修改,可以在函数声明时,对该参数添加const
说明符。这样的话,使用这个函数的人看到原型里面的const
,就知道调用函数前后,参数数组保持不变。
void find(const int* arr, int n);
- 上面示例中,函数
find
的参数数组arr
有const
说明符,就说明该数组在函数内部将保持不变。
- 有一种情况需要注意,如果一个指针变量指向
const
变量,那么该指针变量也不应该被修改。
const int i = 1;
int* j = &i;
* j = 2; // 报错
- 上面示例中,
j
是一个指针变量,指向变量i
,即j
和i
指向同一个地址。j
本身没有const
说明符,但是i
有。这种情况下,j
指向的值也不能被修改。
static
auto
extern
register
register
说明符向编译器表示,该变量是经常使用的,应该提供最快的读取速度,所以应该放进寄存器。但是,编译器可以忽略这个说明符,不一定按照这个指示行事。
register int a;
- 上面示例中,
register
提示编译器,变量a
会经常用到,要为它提供最快的读取速度。
register
只对声明在代码块内部的变量有效。
- 设为
register
的变量,不能获取它的地址。
register int a;
int *p = &a; // 编译器报错
- 上面示例中,
&a
会报错,因为变量a
可能放在寄存器里面,无法获取内存地址。
- 如果数组设为
register
,也不能获取整个数组或任一个数组成员的地址。
register int a[] = {11, 22, 33, 44, 55};
int p = a; // 报错
int a = *(a + 2); // 报错
- 历史上,CPU 内部的缓存,称为寄存器(register)。与内存相比,寄存器的访问速度快得多,所以使用它们可以提高速度。但是它们不在内存之中,所以没有内存地址,这就是为什么不能获取指向它们的指针地址。现代编译器已经有巨大的进步,不管是否使用
register
关键字,都会尽可能使用寄存器,所以不保证一定会把这些变量放到寄存器。
volatile
restrict
restrict
说明符允许编译器优化某些代码。它只能用于指针,表明该指针是访问数据的唯一方式。
int* restrict pt = (int*) malloc(10 * sizeof(int));
- 上面示例中,
restrict
表示变量pt
是访问 malloc 所分配内存的唯一方式。
- 下面例子的变量
foo
,就不能使用restrict
修饰符。
int foo[10];
int* bar = foo;
- 上面示例中,变量
foo
指向的内存,可以用foo
访问,也可以用bar
访问,因此就不能将foo
设为 restrict。
- 如果编译器知道某块内存只能用一个方式访问,可能可以更好地优化代码,因为不用担心其他地方会修改值。
restrict
用于函数参数时,表示参数的内存地址之间没有重叠。
void swap(int* restrict a, int* restrict b) {
int t;
t = *a;
* a = *b;
* b = t;
}
- 上面示例中,函数参数声明里的
restrict
表示,参数a
和参数b
的内存地址没有重叠。