从修饰的对象来看,static 可以修饰局部变量,也可以修饰全局变量,可以修饰函数;可以修饰类中的成员变量以及成员函数。
从生命周期的角度来看,static 修饰的对象的生命周期,与进程的生命周期是一致的。
从作用域的角度来看,局部静态变量的作用域是函数内,全局静态变量的作用域是模块内;类中的静态成员变量和成员函数的作用域,能访问到类的地方都可以访问到静态成员,类中的静态成员同时也受 public,private,protected 权限修饰符的影响。在 c 语言中,静态函数的作用域只在模块内,这样也是一种权限管理,不让其它模块来访问,增强了安全性;同时,多个模块中的两个静态函数的函数名也可以是相同的,给开发带来了方便。
1 static 修饰变量
1.1 局部静态变量
如下代码,在函数 Test() 中声明定义了一个静态变量 static int a = 10,局部静态变量有以下 3 点需要注意:
(1)作用域是函数内
(2)在 static int a = 10,只在启动的时候初始化一次,不像普通的变量,Test() 每次调用的时候都会将 a 赋值成 10。代码中的 a++ 分别是 11,12,13 ...
(3)在声明的时候需要初始化,并且初始化的值必须得是确定的
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void Test(int data) {
// static int a = data; // 这样编译不过,编译的时候就需要确定 error: initializer element is not constant
static int a = 10;
a++;
printf("a = %d, data = %d\n", a, data);
}
int main() {
for (int i = 0; i < 10; i++) {
Test(i);
}
return 0;
}
运行结果如下:
1.2 全局静态变量
在 c 语言中,全局静态变量的作用域就是在源文件内,一个 c 文件中的函数无法访问到另一个 c 文件中声明的静态全局变量。
文件 s0.c 中定义一个静态变量:
static int static_ele = 100;
文件 s0.h 中使用 extern 声明了这个变量:
extern int static_ele;
文件 s2.c 中包含了头文件 s0.h,并且尝试访问变量 static_ele。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "s0.h"
static int a = 100;
int main() {
printf("a = %d, static_ele = %d\n", a, static_ele);
return 0;
}
编译会报错,在 s2.c 中无法访问到 static_ele。
2 static 修饰函数
static 修饰的函数也是只能在 c 文件内部访问,在其它 c 文件不能访问。
文件 s3.c 中定义一个静态函数 static void SayHello():
#include <stdlib.h>
#include <stdio.h>
static void SayHello() {
printf("hello in static function\n");
}
void SayHello1() {
printf("hello1\n");
}
文件 s3.h 中是函数的声明:
void SayHello();
void SayHello1();
文件 s4.c 中包含了头文件 s3.h,并尝试调用函数 SayHello():
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "s3.h"
int main() {
SayHello();
SayHello1();
return 0;
}
编译报错,找不到函数定义:
在 c 语言中,经常使用函数指针,如果静态函数被一个函数指针维护,那么其它模块可以通过函数指针来调用静态函数的。static 关键字是编译阶段检查的语法,在运行时无法检查。
对 s3.c,s3.h,s4.c 进行修改,使用一个函数指针来保存静态函数 SayHello() 的地址,这样的话只要能拿到这个函数指针,就能调用对应的函数。
s3.c:
#include <stdlib.h>
#include <stdio.h>
#include "s3.h"
static void SayHello() {
printf("hello in static function\n");
}
void SayHello1() {
printf("hello1\n");
}
struct FunctionPointer fp = {
.say_hello = SayHello
};
s3.h
void SayHello1();
struct FunctionPointer {
void (*say_hello)();
};
extern struct FunctionPointer fp;
s4.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "s3.h"
int main() {
fp.say_hello();
SayHello1();
return 0;
}
编译运行结果如下:
3 static 修饰类成员
3.1 静态成员变量
静态成员变量属于类,不属于对象。所有的对象共享一份静态成员变量,而不是每个对象都拥有一个。
静态成员变量有以下几点需要注意,在代码中通过注释做了说明。
(1)需要在类外初始化
(2)在类外初始化的时候不能使用 static 修饰
(3)静态成员变量可以被 public,private,protected 修饰,访问权限与非静态成员变量是一致的
#include <iostream>
#include <string>
class Test {
public:
Test() {
std::cout << "Test()" << std::endl;
public_a = 1;
private_a = 2;
protected_a = 3;
}
~Test() {
std::cout << "~Test()" << std::endl;
}
void Do() {
std::cout << "public a = " << public_a << std::endl;
std::cout << "private a = " << private_a << std::endl;
std::cout << "protected a = " << protected_a << std::endl;
}
static int public_a;
private:
static int private_a;
protected:
static int protected_a;
};
// 类的静态成员变量在类外初始化的时候
// 不能再加 static 关键字
// 如果还带 static 关键字,会报错
// error: ‘static’ may not be used when defining (as opposed to declaring) a static data member
// static int Test::public_a = 10;
// static int Test::private_a = 20;
// static int Test::protected_a = 30;
// 类的静态成员变量需要在类外初始化
int Test::public_a = 10;
int Test::private_a = 20;
int Test::protected_a = 30;
int main() {
Test t;
t.public_a = 100;
t.Do();
// t.private_a = 200;
// t.protected_a = 300;
Test::public_a = 1000;
// Test::private_a = 200;
// Test::protected_a = 300;
t.Do();
return 0;
}
运行结果如下图所示:
3.2 静态成员函数
静态成员函数有以下几点需要注意:
(1)可以在类内部声明和实现
(2)也可以在类内部声明,在类外部实现,在类外部实现时,不能 static 修饰
(3)静态成员函数中不能调用非静态成员函数,也不能使用非静态成员变量,因为静态函数中没有 this 指针
#include <iostream>
#include <string>
class Test {
public:
Test() {
std::cout << "Test()" << std::endl;
public_a = 1;
private_a = 2;
protected_a = 3;
}
~Test() {
std::cout << "~Test()" << std::endl;
}
void Do() {
std::cout << "public a = " << public_a << std::endl;
std::cout << "private a = " << private_a << std::endl;
std::cout << "protected a = " << protected_a << std::endl;
}
static void StaticDo() {
// Do(); // error: cannot call member function ‘void Test::Do()’ without object
// public_b = 10; // error: invalid use of member ‘Test::public_b’ in static member function
public_a = 10;
std::cout << "StaticDo" << std::endl;
}
static void StaticDo1();
static int public_a;
int public_b;
private:
static int private_a;
static void PrivateStaticDo() {
std::cout << "Private StaticDo" << std::endl;
}
protected:
static int protected_a;
static void ProtectedStaticDo() {
std::cout << "Protected StaticDo" << std::endl;
}
};
int Test::public_a = 10;
int Test::private_a = 20;
int Test::protected_a = 30;
// error: cannot declare member function ‘static void Test::StaticDo1()’ to have static linkage
/* static */ void Test::StaticDo1() {
std::cout << "StaticDo1()" << std::endl;
}
int main() {
Test t;
t.StaticDo();
t.StaticDo1();
// t.PrivateStaticDo();
// t.ProtectedStaticDo();
// Test::PrivateStaticDo();
// Test::ProtectedStaticDo();
return 0;
}
代码运行结果如下: