7-4 全局变量介绍

第7.3节——局部变量中,我们讨论了局部变量是在函数体内定义的变量。局部变量具有块作用域(仅在其声明所在的代码块内可见),并具有自动生存期(在定义点创建,离开代码块时销毁)。

在C++中,变量也可以在函数外部声明。此类变量称为全局变量global variables


声明全局变量

按惯例,全局变量应在文件开头、包含语句之后、全局命名空间内声明。以下是一个全局变量定义示例:

#include <iostream>

// Variables declared outside of a function are global variables
int g_x {}; // global variable g_x

void doSomething()
{
    // global variables can be seen and used everywhere in the file
    g_x = 3;
    std::cout << g_x << '\n';
}

int main()
{
    doSomething();
    std::cout << g_x << '\n';

    // global variables can be seen and used everywhere in the file
    g_x = 5;
    std::cout << g_x << '\n';

    return 0;
}
// g_x goes out of scope here

上述示例输出:

image


全局变量的作用域

在全局命名空间中声明的标识符具有全局命名空间作用域global namespace scope(通常称为全局作用域global scope,有时也非正式地称为文件作用域file scope),这意味着它们从声明点起直至声明所在文件的结尾都可见。

全局变量声明后,即可在文件内任意位置使用!在上例中,全局变量 g_x 同时被 doSomething() 和 main() 函数调用。

全局变量也可定义在用户自定义命名空间内。下例与前例相同,但将 g_x 从全局作用域移入用户定义的 Foo 命名空间:

#include <iostream>

namespace Foo // Foo is defined in the global scope
{
    int g_x {}; // g_x is now inside the Foo namespace, but is still a global variable
}

void doSomething()
{
    // global variables can be seen and used everywhere in the file
    Foo::g_x = 3;
    std::cout << Foo::g_x << '\n';
}

int main()
{
    doSomething();
    std::cout << Foo::g_x << '\n';

    // global variables can be seen and used everywhere in the file
    Foo::g_x = 5;
    std::cout << Foo::g_x << '\n';

    return 0;
}

尽管标识符 g_x 现已被限制在命名空间 Foo 的作用域内,但该名称仍可通过 Foo::g_x 全局访问,且 g_x 仍属于全局变量。

关键要点
在命名空间内部声明的变量同样属于全局变量。

最佳实践
建议将全局变量定义在命名空间内部,而非全局命名空间中。


全局变量具有静态存储期

全局变量在程序启动时创建(在 main() 开始执行之前),并在程序结束时销毁。这称为静态存储期static duration。具有静态作用域的变量有时被称为静态变量static variables


全局变量的命名

按惯例,部分开发者会在全局变量标识符前添加前缀“g”或“g_”,以表明其全局性。该前缀具有多重作用:

• 避免与全局命名空间中其他标识符发生命名冲突
• 防止无意间造成名称遮蔽(本主题将在第7.5节——变量遮蔽(名称隐藏)中深入探讨)

它有助于表明带前缀的变量在函数作用域之外仍保持存在,因此对它们所做的任何修改也将持续生效。

在用户定义命名空间内定义的全局变量通常省略前缀(因上述前两点在此场景不适用,且前缀命名空间名本身即暗示变量全局性)。但若为突出强调第三点而保留前缀,亦无不可。

最佳实践
建议为全局变量(尤其是定义在全局命名空间中的变量)命名时使用“g”或“g_”前缀,以便与局部变量和函数形参区分开来。

作者注

我们有时会收到读者反馈,询问诸如 g_ 之类的前缀是否可行,因为他们被告知前缀属于匈牙利命名法,而“匈牙利命名法很糟糕”。

反对匈牙利命名法的观点主要源于其将变量类型嵌入变量名的做法,例如nAge中n代表int类型。这种写法在现代C++中已无太大价值。

然而,使用前缀(典型形式为g/g_、s/s_和m/m_)来表示变量的作用域或存储期确实具有实用价值,具体原因将在本节中阐述。


全局变量初始化

与默认未初始化的局部变量不同,具有静态存储期的变量默认采用零初始化。

非常量全局变量可选择性初始化:

int g_x;       // no explicit initializer (zero-initialized by default)
int g_y {};    // value initialized (resulting in zero-initialization)
int g_z { 1 }; // list initialized with specific value

常量全局变量

与局部变量类似,全局变量也可以是常量。与所有常量一样,常量全局变量必须进行初始化。

#include <iostream>

const int g_x;     // error: constant variables must be initialized
constexpr int g_w; // error: constexpr variables must be initialized

const int g_y { 1 };     // const global variable g_y, initialized with a value
constexpr int g_z { 2 }; // constexpr global variable g_z, initialized with a value

void doSomething()
{
    // global variables can be seen and used everywhere in the file
    std::cout << g_y << '\n';
    std::cout << g_z << '\n';
}

int main()
{
    doSomething();

    // global variables can be seen and used everywhere in the file
    std::cout << g_y << '\n';
    std::cout << g_z << '\n';

    return 0;
}
// g_y and g_z goes out of scope here

image

相关内容
我们在第7.10节中更详细地讨论了全局常量——在多个文件中共享全局常量(使用内联变量)。


关于(非常量)全局变量的警示

新手程序员常会倾向于大量使用全局变量,因为它们无需显式传递就能被所有需要它们的函数调用。然而,非常量全局变量通常应完全避免使用!我们将在后续的第7.8节——为何(非常量)全局变量是恶魔 中探讨原因。


快速摘要

// Non-constant global variables
int g_x;                 // defines non-initialized global variable (zero initialized by default)
int g_x {};              // defines explicitly value-initialized global variable
int g_x { 1 };           // defines explicitly initialized global variable

// Const global variables
const int g_y;           // error: const variables must be initialized
const int g_y { 2 };     // defines initialized global const

// Constexpr global variables
constexpr int g_y;       // error: constexpr variables must be initialized
constexpr int g_y { 3 }; // defines initialized global constexpr
posted @ 2026-02-22 09:52  游翔  阅读(0)  评论(0)    收藏  举报