理论上,被调用者可以在没有指针的情况下直接访问调用者中的堆栈变量吗?

问题描述 投票:0回答:1

C 是按值传递的,这意味着每次调用函数时,所有参数都会被复制到堆栈帧中。 C 还 not 支持可以访问/修改词法封闭函数中的局部变量的内部函数。在 C 中“通过引用传递” 的唯一方法是传递一个指针。虽然 C++ 中有引用类型,但这些可能只是幕后的指针。

我在假设的低级类 C 语言中考虑了以下场景。可以在另一个函数内声明一个函数,该函数仅对外部函数可见,并且只能由外部函数调用。如果我的理解是正确的,那么当调用内部函数时,堆栈指针会增加固定数量,假设没有有趣的业务,例如可变大小的对象。因此,随着思考过程的进行,即使在内部函数内部,在外部函数中声明的任何局部变量也会相对于堆栈指针处于固定偏移量。理论上,可以像访问其他局部变量一样访问它们,而无需传递指针。当然,尝试从外部函数外部访问和调用内部函数将尝试访问外部函数中过时的局部变量,并导致未定义的行为。

这里有一个例子:(同样不是C而是一个虚构的类C语言

void (*address_to_inner)(void);
void outer(void) {
    int a = 10;
    void inner(void) {
        printf("%d\n", a);
    }
    inner(); // Prints 10
    address_to_inner = inner; // Not undefined behavior yet but not good
}
void another(void) {
    outer(); // Prints 10
    address_to_inner(); // Undefined behavior because inner() tries to access `a` after it was deallocated
}

我的思维过程是否适用于 x86 或 ARM 等典型架构?低级语言(如 C)不支持某些功能(例如自动内存管理),因为它们本身不受体系结构支持,并且需要太多复杂的幕后工作才能使低级语言可行。但是我的场景是'可行' 对于低级语言还是有任何架构或技术限制我不认为这会使基于堆栈/局部变量和函数调用的工作方式实现这个非常重要?如果不是,为什么不呢?

function assembly stack local-variables calling-convention
1个回答
0
投票

因此,随着思考过程的进行,即使在内部函数内部,在外部函数中声明的任何局部变量也会相对于堆栈指针处于固定偏移量。

这会起作用,尽管您必须排除嵌套函数之间的函数调用,这也排除了它们之间的递归。请注意,Pascal 嵌套函数 可以相互调用,也可以递归调用。

Pascal 基于堆栈的静态链接机制适用于机器的 CPU 寄存器很少的时代,因此大多数 Pascal 程序变量都映射到内存。

另一种适用于具有许多 CPU 寄存器(x64、RISC V、ARM)的机器的可能性可能是在函数内部和函数及其嵌套函数之间对局部变量进行寄存器分配。因此,就像局部变量可能存在于寄存器中一样,非局部变量也可能存在。这也将排除递归,但会产生性能差异。

最后,让我们提一下内联,因为它通过避免为局部变量使用内存,实现了我们对具有大量 CPU 寄存器的机器所期望的很多效率——一旦两个函数通过内联合并,它们就会共享相同的局部变量存储空间;内联甚至可以删除调用者获取的一对地址,然后在被调用者中取消引用,从而允许将这样的局部变量映射到寄存器,而不是地址实际必须具体化时所需的内存。由于内联是通过编译器对函数的分析完成的,因此它可以灵活地允许一个函数调用另一个函数,包括递归——尽管某些结构可能会禁用某些优化。

© www.soinside.com 2019 - 2024. All rights reserved.