作用域就是关于变量在哪些上下文中是可见的。

13.1 Block Scope

这是几乎所有开发者定义变量的作用域。它包括其他语言可能称为“函数作用域”的内容,即在函数内部声明的变量。

基本规则是,如果你在一对大括号限定的代码块中声明了一个变量,那么该变量的作用域就是该代码块。

如果代码块内还有一个嵌套代码块,那么在内层代码块中声明的变量是该内层代码块的局部变量,外层代码块无法访问这些变量。

一旦变量的作用域结束,该变量就不再可被引用,你可以认为它的值已经进入了天空中的“位桶”。

嵌套作用域的示例如下:

#include <stdio.h>

int main(void)
{
    int a = 12;             // 对外层代码块局部,但对内层代码块可见

    if (a == 12) {
        int b = 99;         // 对内层代码块局部,外层代码块不可见

        printf("%d %d\\n", a, b);   // 合法,输出 "12 99"
    }

    printf("%d\\n", a);      // 合法,我们仍在变量 a 的作用域内

    printf("%d\\n", b);      // 非法,变量 b 已超出作用域
}

13.1.1 Where To Define Variables

另一个有趣的事实是,你可以在代码块中的任意位置定义变量(在合理范围内)——它们的作用域仍然是该代码块,但在变量定义之前不能使用它们。

#include <stdio.h>

int main(void)
{
    int i = 0;

    printf("%d\\n", i);       // 合法,输出 "0"

    // printf("%d\\\\n", j);    // 非法——不能在定义 j 之前使用 j

    int j = 5;

    printf("%d %d\\n", i, j); // 合法,输出 "0 5"
}

历史上,C语言要求所有变量必须在代码块中的任何代码之前定义,但在C99标准中,这条规则不再适用。

13.1.2 Variable Hiding

如果在内层作用域和外层作用域中有同名的变量,只要你在内层作用域中运行,内层作用域的变量就会优先使用。也就是说,它会在其生命周期内隐藏外层作用域中的那个变量。

代码示例:

#include <stdio.h>

int main(void)
{
    int i = 10;

    {
        int i = 20;
        printf("%d\\n", i);  // 内层作用域 i,值为20(外层 i 被隐藏)
    }

    printf("%d\\n", i);      // 外层作用域 i,值为10
}

你可能注意到在示例中,我只是在线7处放了一个代码块,而不是使用forif语句来触发代码块!这是完全合法的。有时开发者会想把一堆局部变量放在一起,方便快速计算,也会这样写,但这种情况比较少见。

13.2 File Scope

如果你在块之外定义一个变量,该变量具有文件作用域(file scope)。它在文件中其后出现的所有函数中都是可见的,并且它们之间共享。(例外是如果一个块定义了一个同名变量,它将隐藏文件作用域中的那个变量。)

这最接近你在其他语言中所认为的“全局”作用域。