1. 自动变量类型 auto
auto int i = 1 等同于 int i。 auto 是变量的类型(int 是数据的类型),表示该变量自动利用内存创建和销毁,不需要人为设定。
作用域范围是函数作用域、块作用域,随着函数和块的退出而销毁。
就初始值而言,gcc 编译器和 msvc 编译器得到的结果不同。gcc 编译器下运行,首先会报以下错误,
点击忽略后如下所示,十六进制为 0xcccccccc。
而 msvc 编译器结果如下。
这些结果出现的原因在于编译器对内存的初始化操作不同。gcc编译器会在变量销毁后,将该地址上的值初始化为 0xcccccccc,而 msvc 编译器没有进行初始化。
2. 静态变量类型 static
static 变量类型与 auto 变量类型相对应,为静态类型变量,其所占内存不会因函数退出而销毁。且不赋初值的情况下,系统默认值为 0。
其定义的变量,作用域会变为全局,即文件作用域。举例如下:
void LocalStaticVar(void) {
// 静态变量
// 1. 作用域全局,内存不会因函数退出而销毁
// 2. int 初值默认为 0
static int static_var;
// 自动变量
// 1. 函数、块作用域,随着函数和块退出而销毁
// 2. 没有默认初值
int non_static_var;
printf("static var: %d\n", static_var++);
printf("non static var: %d\n", non_static_var++);
}
int main(){
int a[5] = {1,2,3,4,5};
// TestScope(5, a);
// TestStatic();
LocalStaticVar();
LocalStaticVar();
LocalStaticVar();
return 0;
}
static 类型的变量在定义后,一直将值保留,不在因函数退出而销毁。 此外,-858993460 就是 0xcccccccc,烫的GBK编码是 cccc,烫烫烫此梗来源于此。
3. 寄存器变量类型 register
寄存器变量(register int a)和其他类型变量(int a)的区别在于速度,汇编代码中有所体现。具体区别如下:内存变量传参时必须要把存入寄存器的变量值复制到内存的另一块空间中,再把那块空间的值复制到另一个寄存器,如下图所示:edi 寄存器要先将变量值放入 PTR[rbp-4],再将值从 PTR[rbp-4] 放入 eax。
相比之下,寄存器变量可以直接将一个寄存器中存入的变量值直接复制到另外一个寄存器中,无需额外操作。下图中,edi 寄存器的值直接复制到了 eax 中。
void PassByMemory(int parameter){
printf("%d", parameter);
}
void PassByRegister(register int parameter){
printf("%d", parameter);
}
但在实际使用中无需考虑上述情况,编译器会自动选择最优解,将变量设置为寄存器变量还是内存变量。
4. 块作用域 {}
块作用域范围内的变量只在块内生效,举例如下:
int main(){
{
int a = 0;
}
printf(a); // 编译会报错,a未定义
return 0;
}
5. 函数原型作用域
int sort(int size, int array[size]); 函数原型作用域,这个 size 变量只能在函数声明中使用。且只能在 msvc 编译器下正常运行,在 gcc 编译下不通过,会报以下错误:
1)应输入常量表达式
2)不能分配常量大小为 0 的数组
此外,还有函数作用域与文件作用域,函数作用域为函数参数可以在函数内部使用,而文件作用域则是定义在函数之外的变量,整个文件都可以使用。