1. 存储类别
在函数内部和全局变量中,static关键字用于指定静态存储类别。静态存储类别意味着该变量的内存只会分配一次,并且在程序运行期间都存在,直到程序结束。局部static变量只能在函数内部访问,静态全局变量只能在当前源文件中访问。
在C中,有四种存储类别: auto, register, extern,static。存储类别指的是变量在内存中的存储方式。当我们在函数内部或者模块内部定义一个变量时,会使用auto关键字(默认的存储类别),这意味着该变量的值只在当前函数或块内可见,在函数结束后该变量也会被销毁。如果我们希望变量在函数调用结束后仍然可以保持其状态,那么就需要使用static关键字。使用static关键字定义的变量内存只会分配一次,并在程序运行期间一直存在,直到其值被手动更改或程序结束。
在全局变量中,使用static关键字可以将该变量的作用域限制在当前源文件范围内。这意味着其他源文件无法访问该变量。
#include <stdio.h>
void increment(void);
int main() {
for(int i = 0; i < 3; i++){
increment();
}
return 0;
}
void increment(void) {
static int count = 0;
count++;
printf("Count: %d\n",count);
}
运行上述代码会输出如下结果:
Count: 1
Count: 2
Count: 3
这个程序定义了一个名为increment的函数。该函数中有一个静态局部变量count。每次调用increment函数,该变量会自增1并打印出其当前值。由于变量count被定义为static,因此变量的值会在每次函数调用之间保持不变。使用static关键字时需要注意,因为static变量的初始化只会发生一次,而且不保证其初始值是零。所以,除非你非常确定需要一个特殊的初始值,否则使用static变量时应该自己设定初值。
2. 作用域
在函数内部,嵌套函数中,或者块级作用域内部定义的static变量的作用域只限于当前的作用域内。因此,它们与同名的全局变量或者局部变量不会发生冲突。static关键字也可以用于控制变量和函数的作用域。在函数内部,通过使用static关键字来定义局部静态变量或函数,这些变量只在当前函数内部可见。
外部变量和函数的作用域通常是整个程序的生命周期,在其他模块中可以访问这些变量和函数。但是,如果我们使用static关键字在函数或者全局变量前面定义,就可以将它们的作用域限制在当前源文件内。也就是说,其他文件无法访问这些static变量或函数。
#include <stdio.h>
void printMessage();
static void innerMessage();
static int x = 10;
int main() {
printMessage();
innerMessage();
printf("x from main : %d\n",x);
return 0;
}
void printMessage() {
printf("This is a message from printMessage.\n");
}
static void innerMessage() {
printf("This is a message from innerMessage.\n");
}
这个程序定义了一个名为printMessage的外部函数,以及一个名为innerMessage的内部函数。在innerMessage函数中,使用static关键字来定义一个名为x的静态变量。在main函数中,我们调用printMessage和innerMessage函数,并尝试打印静态变量x的值。
由于innerMessage函数是由static关键字定义的内部函数,因此在其他源文件中无法访问它。同样,静态变量x的作用域也被限制在当前源文件内,因此在main函数中可以访问该变量,但在其他源文件中无法访问。
3. 函数的属性
在函数的声明或者定义中使用static关键字,可以将该函数限制在当前源文件内可见,也被称为内部函数。在函数声明或定义中,使用static关键字修饰函数,可以将该函数定义为内部函数。这意味着外部程序无法使用该函数,得在模块内部才能访问,函数也不会被暴露在头文件中。定义一个内部函数避免了名称冲突,因为该函数名对外部程序是不可见的,不会与其他模块中的同名函数冲突。
#include <stdio.h>
static void messageFromStaticFunction() {
printf("This is a message from static function.\n");
}
int main() {
messageFromStaticFunction();
return 0;
}
这个程序定义了一个名为messageFromStaticFunction的内部函数,并在main函数中调用该函数。使用static关键字在函数声明或者定义中限制了内部函数messageFromStaticFunction的可见性,外部程序无法访问该函数。
4. 结构体成员
在结构体中定义成员变量时,使用static关键字可以将该成员变量与整个结构体数据共享,而不是各自独立赋值。在结构体定义中,可以使用static关键字来定义一个静态成员变量。静态成员变量与结构体共享内存,而不是由每个实例分配独立内存。这个类似于在类中定义静态成员变量。静态成员变量是结构体的开销,所以使用它们需要权衡好内存和性能,适用于在整个生命周期内被多次访问的数据。
#include <stdio.h>
typedef struct {
int len;
static char name[10];
} Person;
int main() {
Person p1, p2;
p1.len = 10;
p2.len = 5;
printf("Length of p1: %d \n", p1.len);
printf("Length of p2: %d \n", p2.len);
p1.name[0] = 'A';
p2.name[0] = 'B';
printf("Name of p1: %c \n", p1.name[0]);
printf("Name of p2: %c \n", p2.name[0]);
return 0;
}
这个程序定义了一个Person结构体,包括一个成员变量len和一个静态成员变量name。由于name是一个静态成员,因此结构体内的每个实例都共享相同的内存空间,该变量不需要手动初始化,可以直接访问。如果不把static关键字放在name之前,那么每个实例都需要一个独立的name数组,造成内存浪费,并且容易出现溢出