C语言
在C语言中,变量根据定义位置的不同,可分为全局变量和局部变量。全局变量是指在函数外定义的变量,它的作用域通常从定义位置开始一直持续到源文件结束,生命周期贯穿整个程序运行期间。
// 例1
#include <stdio.h>
int a = 100;
int main()
{
printf("%d\n", a);
}
例1中的变量a定义在函数外,因此属于全局变量。全局变量在程序启动时分配存储空间,在程序结束时释放,因此即使没有显式初始化,也会自动初始化为0,如例2所示。
// 例2
#include <stdio.h>
int a;
int main()
{
printf("%d\n", a);
}
输出:
0
全局变量可以在其他位置通过extern关键字进行声明,如例3所示。
// 例3
#include <stdio.h>
int a = 111;
int main()
{
extern int a;
printf("%d\n", a);
}
输出:
111
extern关键字表示变量定义在其他位置,此处仅进行声明,不会重新分配存储空间。如果extern声明的变量不存在,则链接阶段会报错。
局部变量是指在函数体或代码块内部定义的变量,其作用域仅限于所在代码块。
// 例4
#include <stdio.h>
int main()
{
int a = 111;
printf("%d\n", a);
}
例4中的变量a定义在main函数内部,因此属于局部变量。局部变量在进入代码块时创建,离开代码块时销毁,其生命周期通常与函数调用过程一致。与全局变量不同,局部变量若未初始化,其值是不确定的,如例5所示。
// 例5
#include <stdio.h>
int main()
{
int a;
printf("%d\n", a);
}
例5能够通过编译,但输出结果未定义,编译器通常会给出警告。当局部变量与全局变量同名时,局部变量会遮蔽全局变量,如例6所示。
// 例6
#include <stdio.h>
int a = 100;
int main()
{
int a = 200;
printf("%d\n", a);
}
输出:
200
例6中的局部变量a优先级更高,因此读取的是局部变量。如果全局变量使用static修饰,则其链接属性会变为内部链接(internal linkage),即只能在当前源文件访问。
// a.c
static int a = 100;
// b.c
extern int a;
上述代码会导致链接失败,因为static全局变量不会导出到其他源文件。
Python
在Python中,变量根据作用域的不同,也可以分为全局变量和局部变量。通常情况下,在模块顶层定义的变量属于全局变量,其作用域为整个模块,如例7所示。
# 例7
a = 100
print(a)
例7中的a定义在模块顶层,因此属于全局变量。函数内部可以直接读取全局变量,如例8所示。
# 例8
a = 111
def func():
print(a)
func()
输出:
111
虽然函数内部可以读取全局变量,但如果在函数内部对同名变量赋值,则默认会创建局部变量。
# 例9
a = 111
def func():
a = 222
print(a)
func()
print(a)
输出:
222
111
例9中函数内部的a是局部变量,不会赋值全局变量。如果需要赋值全局变量,则需要使用global关键字。在Python中,如果函数内部既读取又赋值同名变量,则该变量会被整体视为局部变量,如例11所示。
# 例11
a = 111
def func():
print(a)
a = 222
func()
输出:
UnboundLocalError:
local variable 'a' referenced before assignment
关于例11所示结果的进一步阐述,可以参考下面的博客。
Python:标识符的作用域解析
https://chenzhang.blog.csdn.net/article/details/132156898
Bash
在Bash中,变量默认属于全局变量,如例13所示。
# 例13
a=111
echo $a
输出:
111
例13中的a可以在整个Shell脚本中访问。在函数内部定义变量时,如果不使用local关键字,则该变量仍然是全局变量,如例14所示。
# 例14
func()
{
a=222
}
func
echo $a
输出:
222
例14中的a虽然定义在函数内部,但仍然赋值了全局变量。如果希望变量仅在函数内部有效,则需要使用local关键字,如例15所示。
# 例15
a=111
func()
{
local a=222
echo $a
}
func
echo $a
输出:
222
111
例15中的local a语句创建了局部变量,因此不会影响全局变量。当local变量与全局变量同名时,局部变量会遮蔽全局变量,如例16所示。
# 例16
a=111
func()
{
local a=222
echo $a
}
func
echo $a
输出:
222
111
Bash中不会出现类似Python中那种UnboundLocalError,如例17所示。原因在于,Python在函数定义时就会分析作用域(静态作用域、LEGB规则);而Bash在执行时才查找变量(动态查找)。
# 例17
a=111
func()
{
echo $a
local a=222
}
func
输出:
111
Tcl
在Tcl中,变量默认根据所在位置决定作用域。在proc之外定义的变量属于全局变量,如例19所示。
# 例19
set a 111
puts $a
输出:
111
例19中的a属于全局变量。在proc内部通过set创建的变量,默认属于局部变量,如例20所示。
# 例20
proc func {} {
set a 222
puts $a
}
func
输出:
222
proc内部默认无法直接读取和赋值全局变量,如果需要访问全局变量,需要使用global命令(后续代码更简洁,适合频繁访问)或使用作用域解析符::(变量来源更明确,适合偶尔访问
)访问全局变量,如例21所示。
# 例21
set a 111
set b 111
proc func {} {
global a
set a 222
set ::b 222
}
func
puts $a
puts $b
输出:
222
222
需要注意的是,使用global命令要求变量在之前未定义,例22会报错。
# 例21
set a 111
set b 111
proc func {} {
set a 222
global a
set ::b 222
}
func
puts $a
puts $b