文章

关键字 Static

关键字 Static

[TOC]

1. static变量

1.1 静态局部变量

static关键字在局部变量中的应用是其最常见的用法之一。

静态局部变量仅在函数第一次调用时初始化,而在函数调用结束后仍然保留其值

这对于需要在多次调用之间保留状态的函数非常有用。

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
void demoStaticLocalVariable() {
    static int count = 0;
    count++;
    std::cout << "Function called " << count << " times." << std::endl;
}
int main() {
    demoStaticLocalVariable();
    demoStaticLocalVariable();
    demoStaticLocalVariable();
    return 0;
}

在上面的例子中,count是一个静态局部变量。每次调用demoStaticLocalVariable函数时,count都会递增,但其值在函数调用之间保持不变。这提供了一种在函数调用之间保持状态的简便方法

另外,当你在一个类的成员函数中声明一个变量为 static,这个变量的存储持续性变为静态的,它就成为了与类相关联而非与任何特定对象相关联的变量。这意味着无论你创建多少个对象,静态局部变量只有一份拷贝,并且其值在对象之间共享。静态局部变量的生命周期从它们被初始化开始,直到程序结束。它们的初始化只会在第一次进入声明它们的函数域时发生一次,后续的函数调用不会重新初始化它们。

1.2 静态全局变量

与静态局部变量类似,静态全局变量也只初始化一次,但其作用域超出了单个函数

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
static int globalCount = 0;
void demoStaticGlobalVariable() {
    globalCount++;
    std::cout << "Function called " << globalCount << " times." << std::endl;
}
int main() {
    demoStaticGlobalVariable();
    demoStaticGlobalVariable();
    demoStaticGlobalVariable();
    return 0;
}

在这个例子中,globalCount是一个静态全局变量。无论在哪个函数中调用,globalCount都会在函数调用之间保持状态。

1.3 全局变量和静态全局变量的区别

在C++(以及C)中,全局变量和静态全局变量主要的区别在于它们的链接性(linkage),也就是它们的可见性或作用域范围。1

除了链接性的区别,静态全局变量和非静态全局变量在其他方面是相似的。它们都有静态存储期(static storage duration),意味着它们在程序的整个运行期间都存在,并且它们会在程序启动之前被初始化(如果没有显式初始化,它们会被自动初始化为0)。

(1) 全局变量:

  • 全局变量在整个程序中都是可见的,除非它被隐藏了(例如,因为有同名的局部变量)。
  • 它们在程序的任何地方都可以被访问(前提是它们已经被声明了,通常使用extern关键字在其他文件中声明)。
  • 全局变量有外部链接性(external linkage),意味着在其他文件中可以通过extern声明访问同一个变量。

(2) 静态全局变量:

  • 静态全局变量只在定义它的文件内可见,这被称为文件作用域。它们对其他文件是隐藏的。
  • 它们在定义它们的文件之外不能被直接访问(即使使用extern关键字也不行)。
  • 静态全局变量有内部链接性(internal linkage),意味着即使其他文件中有相同名字的变量,它们也是完全不同的变量。

下面是一个示例来说明这两者间的区别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// File1.cpp
#include <iostream>

int globalVar = 0; // 全局变量
static int staticGlobalVar = 0; // 静态全局变量

void incrementAndPrint() {
    globalVar++;
    staticGlobalVar++;
    std::cout << "globalVar in File1: " << globalVar << "\n";
    std::cout << "staticGlobalVar in File1: " << staticGlobalVar << "\n";
}

// File2.cpp
#include <iostream>
extern int globalVar; // 使用extern关键字声明外部链接的全局变量

// extern int staticGlobalVar; // 错误!staticGlobalVar在这个文件中不可见

void anotherFunction() {
    globalVar++;
    // staticGlobalVar++; // 错误:这个变量在File2中不可见
    std::cout << "globalVar in File2: " << globalVar << "\n";
}

int main() {
    incrementAndPrint(); // 输出 globalVar 和 staticGlobalVar 的值
    anotherFunction(); // 只会影响 globalVar 的值
    incrementAndPrint(); // 再次输出 globalVar 和 staticGlobalVar 的值
    return 0;
}

在这个例子中,File1.cpp 定义了一个全局变量 globalVar 和一个静态全局变量 staticGlobalVar

globalVar 可以在 File2.cpp 中被访问和修改,因为它有外部链接性。

staticGlobalVar 只能在 File1.cpp 中被访问和修改,因为它有内部链接性,它在 File2.cpp 中是不可见的。

1.4 static成员变量

在类中,static关键字还可以用于声明静态成员变量。静态成员变量是类的所有实例共享的,而不是每个实例都有自己的一份。

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
class MyClass {
public:
    static int staticMemberVariable;
};
int MyClass::staticMemberVariable = 0;
int main() {
    MyClass obj1;
    MyClass obj2;
    obj1.staticMemberVariable = 42;
    std::cout << obj2.staticMemberVariable << std::endl;  // 输出 42
    return 0;
}

在这个例子中,staticMemberVariable是MyClass的静态成员变量。即使有多个MyClass的实例,它们都共享相同的staticMemberVariable。

2. 函数的static修饰

2.1 静态函数

static关键字还可用于修饰函数,使其成为静态函数。静态函数只能在声明它的文件中可见,作用范围也被限制在当前文件内,无法被其他文件引用。

这有利于模块化设计,减少不必要的外部依赖。这有助于限制函数的可见性,提高代码的安全性。可以避免在其他文件中引用不应被外部访问的函数。

例如,现有一文件file1.c2

1
2
3
4
5
6
7
8
9
10
11
12
13
// file1.c  
#include <stdio.h>  

// 静态函数  
static void secretFunction() { 
6    printf("This is a secret function!\n");  
}  

// 可以调用静态函数  
int main(int argc, char *argv[]) {  
    secretFunction(); 
    return 0;  
}

file2.c文件中,调用file1.c中的secretFunction函数,则会失败

1
2
3
4
5
6
7
8
9
// file2.c  
// 错误:无法在其他文件中访问静态函数 
extern void secretFunction(); 

int main(int argc, char *argv[]) { 
    // 错误:无法在其他文件中访问静态函数  
    secretFunction(); 
    return 0;  
}

2.2 静态类成员函数

在类中,static关键字可以用于声明静态成员函数。与普通成员函数不同,静态成员函数不依赖于类的实例,可以直接通过类名调用。

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
class MyClass {
public:
    static void staticMemberFunction() {
        std::cout << "This is a static member function." << std::endl;
    }
};
int main() {
    MyClass::staticMemberFunction();
    return 0;
}

在这个例子中,staticMemberFunction是一个静态类成员函数。通过类名MyClass直接调用,而不需要创建类的实例。

参考文章34

本文由作者按照 CC BY 4.0 进行授权