# 2008-05-06 10:34:30 by Sean Zhang
核心是调用栈(call stack frame)的访问
我的理解。核心是调用栈(call stack frame)的访问。
stack frame可以理解为程序执行的环境(context)。当调用一个函数时,可以认为是在当前的frame里新建了一个stack frame,函数在这个新建的frame里执行,默认情况下它能访问到的变量也局限于这个frame。要访问这个frame之外的变量,有两种思路。
这就要告诉程序要访问某个特定frame的位置。比如下面的例子。
uplevel #0 {puts $var_name} uplevel #1 {puts $var_name} uplevel 1 {puts $var_name} uplevel 2 {puts $var_name}
其中#0, #1 是stack frame绝对位置。#0表示最顶层,也就是所谓”全局“那一层。第三行,第四行的1,2表示当前frame的上一层frame,和再上一层frame。上面的例子都表示在指定的stack frame时执行相应的命令,其中变量"var_name"也应该是声明在相应的frame里的。
"uplevel"的用法简单来说也就是如此。"upvar"则是把指定frame里的变量拿到当前frame里来用。比如:
upvar 1 var_name_outside var_name_inside
通过这样的声明之后,当前frame里访问变量"var_name_inside"实质上就是访问上一层frame里的变量"var_name_outside"。这跟C语言中的引用很类似。
说到这里,我们再看下面两条语句:
global var_name upvar #0 var_name var_name
它们是不是有着相同的作用呢。但global很大程度上要求你必须知道变量的名字,而upvar则不需要。比如自己写一个printvar的命令的话。
# This does not work! proc printvar_global {var_name} { global $var_name puts $var_name } # This works!proc printvar_upvar {var_name} { upvar #0 $var_name name puts $name }
这个例子可以很好的说明upvar的妙处来。