标识符的作用域是程序中可以直接访问标识符的部分。在 C 中,所有标识符都是词法(或静态)范围的。C 作用域规则可以涵盖在以下两个类别中。
基本上有4个作用域规则:
让我们通过示例讨论每个作用域规则。
文件作用域:这些变量通常在程序顶部的所有函数和块之外声明,并且可以从程序的任何部分访问。这些也称为全局范围变量,因为它们可以被全局访问。
示例 1:
输出:
注意:要限制仅访问当前文件,可以将全局变量标记为静态。
块作用域:块是一组包含在左右大括号内的语句,即分别为“{”和“}”。块可以嵌套在 C 中(一个块中可能包含其他块)。在块内声明的变量可在块内和该块的所有内部块中访问,但在块外不可访问。基本上,这些对于定义变量的块来说是本地的,并且无法在外部访问。
输出:
输出:
现在可能会出现关于变量访问范围的各种问题:
如果内部块本身有一个同名变量怎么办?
如果内部块声明了一个与外部块声明的变量同名的变量,则外部块变量的可见性在内部块声明的点结束。
传递给函数的函数和参数呢?
函数本身就是一个块。函数的参数和其他局部变量遵循相同的块范围规则。
可以在另一个后续块中访问该块的变量吗?
不可以,在块中声明的变量只能在块内部和该块的所有内部块中访问。
例如,以下程序会产生编译器错误。
错误:
输出:
范围 | 意义 |
---|---|
文件作用域 | 标识符的作用域从文件的开头开始,到文件的结尾结束。它仅指那些在所有函数之外声明的标识符。文件作用域的标识符在整个文件中都是可见的 具有文件作用域的标识符是全局的 |
块作用域 | 标识符的作用域从块/'{'的开头开始,到块/'}'的末尾结束。具有块作用域的标识符是其块的本地标识符 |
函数原型作用域 | 在函数原型中声明的标识符在原型中是可见的 |
函数作用域 | 函数作用域从函数的开头开始,到函数的关闭结束。函数作用域仅适用于标签。声明的标签用作 goto 语句的目标,并且 goto 和标签语句必须在同一个函数中 |
// C program to illustrate the global scope
#include <stdio.h>
// Global variable
int global = 5;
// global variable accessed from
// within a function
void display()
{
printf("%dn", global);
}
// main function
int main()
{
printf("Before change within main: ");
display();
// changing value of global
// variable from main function
printf("After change within main: ");
global = 10;
display();
}
Before change within main: 5 After change within main: 10示例 2:
// filename: file1.c
int a;
int main(void)
{
a = 2;
}
// filename: file2.c
// When this file is linked with file1.c, functions
// of this file can access a
extern int a;
int myfun()
{
a = 2;
}
#include <stdio.h>
// Driver Code
int main()
{
{
int x = 10, y = 20;
{
// The outer block contains
// declaration of x and
// y, so following statement
// is valid and prints
// 10 and 20
printf("x = %d, y = %dn", x, y);
{
// y is declared again,
// so outer block y is
// not accessible in this block
int y = 40;
// Changes the outer block
// variable x to 11
x++;
// Changes this block's
// variable y to 41
y++;
printf("x = %d, y = %dn", x, y);
}
// This statement accesses
// only outer block's
// variables
printf("x = %d, y = %dn", x, y);
}
}
return 0;
}
x = 10, y = 20 x = 11, y = 41 x = 11, y = 20函数原型作用域:这些变量作用域包括在函数参数列表中。这些变量的作用域从函数原型中的声明之后开始,一直到声明列表的末尾。这些作用域不包括函数定义,而只是函数原型。 例子:
// C program to illustrate
// function prototype scope
#include <stdio.h>
// function prototype scope
//(not part of a function definition)
int Sub(int num1, int num2);
// file scope
int num1;
// Function to subtract
int Sub(int num1, int num2)
{
return (num1-num2);
}
// Driver method
int main(void)
{
printf("%dn", Sub(10,5));
return 0;
}
5
函数作用域:函数作用域从函数的打开开始,到函数的关闭结束。功能范围仅适用于标签。声明的标签用作转到语句的目标,并且 goto 和标签语句必须在同一个函数中。
例子:
void func1()
{
{
// label in scope even
// though declared later
goto label_exec;
label_exec:;
}
// label ignores block scope
goto label_exec;
}
void funct2()
{
// throwserror:
// as label is in func1() not funct2()
goto label_exec;
}
int main()
{
{
int x = 10;
}
{
// Error: x is not accessible here
printf("%d", x);
}
return 0;
}
prog.c: In function 'main': prog.c:8:15: error: 'x' undeclared (first use in this function) printf("%d", x); // Error: x is not accessible here ^ prog.c:8:15: note: each undeclared identifier is reported only once for each function it appears in例子:
// C program to illustrate scope of variables
#include<stdio.h>
int main()
{
// Initialization of local variables
int x = 1, y = 2, z = 3;
printf("x = %d, y = %d, z = %dn",
x, y, z);
{
// changing the variables x & y
int x = 10;
float y = 20;
printf("x = %d, y = %f, z = %dn",
x, y, z);
{
// changing z
int z = 100;
printf("x = %d, y = %f, z = %dn",
x, y, z);
}
}
return 0;
}
x = 1,y = 2,z = 3 x = 10,y = 20.000000,z = 3 x = 10,y = 20.000000,z = 100