编译器如何实现变量的范围? 我的意思是,当我们说静态变量时,范围仅限于在定义静态变量的同一文件中定义的块或函数? 如何在机器级别或内存级别实现这一目标?
这种限制实际上是如何实现的?
在程序运行时如何解决这个范围?
答案 0 :(得分:8)
在机器级别根本无法实现。编译器在实际生成机器代码之前检查范围。 C的规则由编译器实现,而不是由机器实现。编译器必须检查那些规则,机器没有也不能。
关于编译器如何检查这一点的非常简单的解释:
每当引入一个作用域时,编译器会给它一个名称并将其放在一个结构(树)中,这样可以很容易地确定该作用域相对于其他作用域的位置,并将其标记为当前范围。声明变量时,将其分配给当前作用域。访问变量时,会在当前范围中查找。如果未找到,则查找树以查找当前树之上的范围。这一直持续到我们达到最高范围。如果仍然没有找到变量,那么我们就会违反范围。
答案 1 :(得分:1)
编译器内部,其实现已定义。例如,如果我正在编写编译器,我将使用树来定义“范围”,它肯定是二叉树中的符号表。
有些人会使用任意深度的哈希表。它的所有实现定义。
答案 2 :(得分:0)
我不是100%确定我明白你在问什么,但如果你的意思是“如何将静态变量和函数存储在最终程序中”,那就是实现定义。
也就是说,存储这些变量和函数的常用方法与任何其他全局符号(以及一些非全局符号)位于同一位置 - 不同之处在于它们不是“导出”的,因此不可见在尝试链接到我们软件的任何外部代码中。
换句话说,一个程序中包含以下内容:
int var;
static int svar;
int func() { static int func_static; ... }
static int sfunc() { ... }
...在内存中可能有以下布局(假设我们的数据从0xF000
开始,并在0xFF00
处运行):
0xF000: var
0xF004: svar
0xF008: func.func_static
...
0xFF00: func's data
0xFF40: sfunc's data /* assuming we needed 0x40 bytes for `func`! */
但是,导出列表只包含非静态符号,即导出符号:
var v 0xF000
func f 0xFF00
再次 - 请注意,虽然静态数据仍然写入文件(它必须存储在某处!),但它不会被导出;通俗地说,我们的计划并没有告诉任何人它包含svar
,sfunc
和类似的内容。
在Unices中,您可以列出库或程序使用nm
工具导出的符号:http://unixhelp.ed.ac.uk/CGI/man-cgi?nm; Windows确实存在类似的工具(GnuWin32可能有类似的东西)。
实际上,可执行代码通常与数据分开存储(例如,可以保护它不受写入影响),并且可以重新排序它们以最小化内存使用和缓存未命中,但这个想法保持不变。
当然,可以应用优化 - 例如,静态函数可以在其每个invokation中内联,这意味着根本不为函数本身生成代码,因此它本身不存在。