C++全局变量简介与作用域、初始化、命名规范

什么是全局变量?

在《局部变量》中,我们讨论了定义于函数体内的变量——局部变量。它们具有块作用域(仅在声明所在的代码块可见)以及自动存储期(定义时创建,离开块时销毁)。

在 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() 执行前)创建,在程序结束时销毁,这称为静态存储期。拥有静态存储期的变量有时也称为静态变量

全局变量命名约定

部分开发者按惯例为全局变量添加 gg_ 前缀,以标识其全局属性:

  1. 降低与全局命名空间其他标识符冲突的风险;
  2. 防止意外名称遮蔽(参见 7.5 课《变量遮蔽》);
  3. 提示该变量在函数调用间持续存在,修改会保留。

位于用户自定义命名空间内的全局变量常省略此前缀,因为命名空间已降低冲突风险;保留前缀亦可作为提醒。

最佳实践
为全局变量(尤其是位于全局命名空间者)使用 gg_ 前缀,以区分于局部变量和形参。

作者注
有读者担心 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 }; // 必须初始化

关注公众号,回复"cpp-tutorial"

可领取价值199元的C++学习资料

公众号二维码

扫描上方二维码或搜索"cpp-tutorial"