什么是全局变量?
在《局部变量》中,我们讨论了定义于函数体内的变量——局部变量。它们具有块作用域(仅在声明所在的代码块可见)以及自动存储期(定义时创建,离开块时销毁)。
在 C++ 中,变量也可以在函数外部声明,这类变量称为全局变量。
声明全局变量
按照惯例,全局变量通常置于文件顶部、包含指令之后、全局命名空间之中。示例:
#include <iostream>
// 在函数外声明的变量为全局变量
int g_x {}; // 全局变量 g_x
void doSomething()
{
// 全局变量在整个文件内均可见可用
g_x = 3;
std::cout << g_x << '\n';
}
int main()
{
doSomething();
std::cout << g_x << '\n';
g_x = 5;
std::cout << g_x << '\n';
return 0;
}
// g_x 在此处离开作用域
程序输出:
3
3
5
全局变量的作用域
在全局命名空间中声明的标识符具有全局命名空间作用域(通常简称“全局作用域”,有时也称“文件作用域”)。这意味着从声明点到文件末尾,该标识符均可见。
声明后,全局变量可在文件中任意位置使用。上例中,g_x
同时被 doSomething()
与 main()
访问。
全局变量也可定义于用户自定义命名空间内:
#include <iostream>
namespace Foo // Foo 位于全局作用域
{
int g_x {}; // 此时 g_x 位于 Foo 命名空间内,但仍是全局变量
}
void doSomething()
{
Foo::g_x = 3;
std::cout << Foo::g_x << '\n';
}
int main()
{
doSomething();
std::cout << Foo::g_x << '\n';
Foo::g_x = 5;
std::cout << Foo::g_x << '\n';
return 0;
}
关键洞察
命名空间内声明的变量同样是全局变量。
最佳实践
优先将全局变量置于命名空间,而非直接放在全局命名空间。
全局变量具有静态存储期
全局变量在程序启动时(main()
执行前)创建,在程序结束时销毁,这称为静态存储期。拥有静态存储期的变量有时也称为静态变量。
全局变量命名约定
部分开发者按惯例为全局变量添加 g
或 g_
前缀,以标识其全局属性:
- 降低与全局命名空间其他标识符冲突的风险;
- 防止意外名称遮蔽(参见 7.5 课《变量遮蔽》);
- 提示该变量在函数调用间持续存在,修改会保留。
位于用户自定义命名空间内的全局变量常省略此前缀,因为命名空间已降低冲突风险;保留前缀亦可作为提醒。
最佳实践
为全局变量(尤其是位于全局命名空间者)使用 g
或 g_
前缀,以区分于局部变量和形参。
作者注
有读者担心 g_
等前缀属于“匈牙利命名法”而应避免。反对匈牙利命名法主要是反对将类型信息硬编码到变量名(如 nAge
)。
然而,用前缀表示作用域或存储期(g/g_
、s/s_
、m/m_
)在现代 C++ 中仍有价值,如上所述。
全局变量初始化
与默认未初始化的局部变量不同,具有静态存储期的变量默认零初始化。 非 const 全局变量可显式初始化:
int g_x; // 未显式初始化,默认零初始化
int g_y {}; // 值初始化,结果为零初始化
int g_z { 1 }; // 列表初始化为特定值
常量全局变量
全局变量亦可为常量,且必须初始化:
#include <iostream>
const int g_x; // 错误:常量必须初始化
const int g_y { 1 }; // 正确
constexpr int g_z { 2 }; // 正确
void doSomething()
{
std::cout << g_y << '\n';
std::cout << g_z << '\n';
}
int main()
{
doSomething();
std::cout << g_y << '\n' << g_z << '\n';
return 0;
}
相关内容
关于全局常量的更多讨论见 7.10 课《使用 inline 变量在多个文件中共享全局常量》。
关于(非常量)全局变量的警告
初学者常因“无需显式传递”而滥用全局变量。然而,应尽量避免使用非常量全局变量,原因将在 7.8 课《为何(非 const)全局变量是祸根》中详述。
快速小结
// 非常量全局变量
int g_x; // 默认零初始化
int g_x {}; // 显式值初始化
int g_x { 1 }; // 显式列表初始化
// const 全局变量
const int g_y { 2 }; // 必须初始化
// constexpr 全局变量
constexpr int g_z { 3 }; // 必须初始化