05、作用域介绍

厨子大约 5 分钟C语言基础程序程序厨

本文主要介绍下C语言中作用域的概念。

作用域是编程中的一个核心概念,它定义了变量、函数等标识符的可访问范围。

本文会深入探讨C语言中的作用域规则,包括全局作用域、文件作用域(静态全局作用域)、函数作用域,以及块作用域。

全局作用域

全局作用域是指在程序的所有部分都可以访问的标识符。在C语言中,全局变量和全局函数拥有全局作用域。当你在函数外部声明一个变量或函数时,它们就拥有了全局作用域。

// global_example.c
#include <stdio.h>

int globalVar = 100; // 全局变量

void globalFunction() {
    printf("This is a global function.\n");
}

void anotherFunction() {
    printf("Accessing global variable: %d\n", globalVar);
    globalFunction();
}

int main() {
    printf("Global variable in main: %d\n", globalVar);
    globalFunction();
    anotherFunction();
    return 0;
}

在上例,globalVarglobalFunction都可以在任何函数内部被访问,包括main函数和anotherFunction函数。

多文件共享全局变量

当一个项目包含多个源文件时,可能需要在多个文件中访问同一个全局变量。这时,可以使用extern关键字来声明变量,而不定义它,告诉编译器该变量在其他地方定义。

file1.c:

#include <stdio.h>

int sharedVar = 50; // 定义全局变量

file2.c:

#include <stdio.h>

extern int sharedVar; // 声明全局变量

void printSharedVar() {
    printf("Shared variable value: %d\n", sharedVar);
}

main.c:

#include <stdio.h>

extern int sharedVar; // 再次声明,以便在main中使用
void printSharedVar(); // 声明file2.c中的函数

int main() {
    printf("Initial shared variable value: %d\n", sharedVar);
    sharedVar = 100; // 修改全局变量的值
    printSharedVar(); // 调用file2.c中的函数,验证值的变化
    return 0;
}

编译并链接这些文件后,程序将正常运行,显示全局变量sharedVar的修改效果。

限制全局变量的可见性

使用static关键字可以将全局变量的作用域限制在定义它的文件内,这样其他文件就无法访问这个变量。

file_static.c:

#include <stdio.h>

static int fileScopeVar = 200; // 文件作用域变量

void printFileScopeVar() {
    printf("File scope variable: %d\n", fileScopeVar);
}

在这个文件中,fileScopeVar只能在file_static.c内部被访问,其他文件即使使用extern声明也无法访问它。

其实整体比较好理解,如果在一个源文件中定义了一个全局变量,那这个变量的作用域就是整个源文件。

比如:

// test.cc
int global = 1;

void func() {
  cout << global;
}

void func2() {
  cout << global;
}

注意这里global的作用域是在作用在整个源文件中,只在本文件内可访问。

而一个应用程序可以由多个源文件组成,在其他文件其实也可以访问这个global变量,但是不能直接访问,比如:

// test2.cc
void func() {
  cout << global;
}

void func2() {
  cout << global;
}

这样是不能编译通过的,这里需要在test2.cc中使用extern声明一下:

// test2.cc
extern int global;
void func() {
  cout << global;
}

void func2() {
  cout << global;
}

这里的extern int global;表示在声明一个global变量,但却不在此文件内定义,它的定义会存在于其他源文件中。

通过extern声明后,在test2.cc中就可以访问test.cc中的global全局变量了。

那有没有办法定义一个全局变量,只在当前源文件内可访问,其它源文件不可见呢?

可以,加个static关键字:

// test.cc
static int global = 1;
void func() {
  cout << global;
}

void func2() {
  cout << global;
}

static在这里表示局部的含义,表示只在当前源文件可见。在开发的过程中大家如果有上面的需求(只希望在源文件内可见),无论是变量还是函数,建议都使用static修饰。

函数作用域

函数作用域主要指的是函数内部定义的变量,这些变量只能在函数体内被访问,函数外部无法访问。

所有在函数内部定义的变量默认具有函数作用域(也称为局部变量)。

#include <stdio.h>

void exampleFunction() {
    int localVar = 10; // 局部变量
    printf("Local variable inside function: %d\n", localVar);
}

int main() {
    exampleFunction();
    // printf("Trying to access localVar: %d\n", localVar); // 错误:localVar未声明
    return 0;
}

main函数中尝试访问localVar会导致编译错误,因为localVar的作用域仅限于exampleFunction内部。

块作用域

块作用域是指由一对花括号{}包围的代码块内定义的变量的作用域。任何在块内定义的变量只能在该块内访问,包括函数内的局部块。

#include <stdio.h>

void blockScopeExample() {
    int a = 10;
    if (1) {
        int b = 20; // 块作用域变量
        printf("Inside if block, b = %d\n", b);
    }
    // printf("Trying to access b: %d\n", b); // 错误:b未声明
    printf("Outside if block, a = %d\n", a);
}

int main() {
    blockScopeExample();
    return 0;
}

在这个例子中,变量b的作用域仅限于if语句块内,一旦出了这个块,b就无法被访问。

静态变量

在C语言中,static关键字除了用于限制全局变量的作用域外,还可以用于函数内的局部变量,使其具有静态存储持续时间。这意味着即使函数执行完毕,变量的值也不会丢失,下次调用该函数时,变量将保持上次的值。

#include <stdio.h>

void staticExample() {
    static int count = 0; // 静态局部变量
    count++;
    printf("Count = %d\n", count);
}

int main() {
    staticExample();
    staticExample();
    staticExample();
    return 0;
}

每次调用staticExample函数时,count的值都会递增,因为count是静态局部变量,其生命周期贯穿程序的整个运行过程,但其作用域仍限制在staticExample函数内。

注意:上面的各种概念可能和书本上的不太一样,我是本着易于理解的角度来介绍的,可能有些概念整理的不是很书面且标准。