Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如果程序计数器指向要执行的下一条指令的地址,帧指针做什么?_C_Callstack - Fatal编程技术网

C 如果程序计数器指向要执行的下一条指令的地址,帧指针做什么?

C 如果程序计数器指向要执行的下一条指令的地址,帧指针做什么?,c,callstack,C,Callstack,如果程序计数器指向要执行的下一条指令的地址,帧指针做什么 通常是返回地址(例如,有时刚刚超过最后一个参数)。关键是帧指针在方法的生命周期内是固定的,而堆栈指针在执行期间可能会移动 这非常依赖于实现(更多的是机器概念,而不是真正的语言概念) 摘自您对另一个答案的评论: 哇。。。堆栈指针?。。。这是程序计数器的同义词吗 阅读关于这个问题的文章。基本上,调用堆栈存储当前方法的本地数据(本地变量、方法的参数和调用方的返回地址)。堆栈指针指向分配新空间的结构的顶部(通过将堆栈指针移到“更高”) 很好的讨论

如果程序计数器指向要执行的下一条指令的地址,帧指针做什么

通常是返回地址(例如,有时刚刚超过最后一个参数)。关键是帧指针在方法的生命周期内是固定的,而堆栈指针在执行期间可能会移动

这非常依赖于实现(更多的是机器概念,而不是真正的语言概念)

摘自您对另一个答案的评论:


哇。。。堆栈指针?。。。这是程序计数器的同义词吗

阅读关于这个问题的文章。基本上,调用堆栈存储当前方法的本地数据(本地变量、方法的参数和调用方的返回地址)。堆栈指针指向分配新空间的结构的顶部(通过将堆栈指针移到“更高”)

很好的讨论,包括例子和所有内容


简言之:FP指向堆栈上函数帧内的固定点(并且在函数执行期间不会更改),因此所有传递的参数和函数的局部(“自动”)变量都可以通过FP的偏移量进行访问(而SP可以在函数执行期间更改,PC肯定会更改;-)这不是一个真正的C问题,因为它完全依赖于编译器

但是,堆栈帧是考虑当前函数及其父函数的有用方法。通常,帧指针指向堆栈上的特定位置(对于给定的堆栈深度),从中可以定位传入的参数以及局部变量

这里有一个例子,假设您调用一个函数,该函数接受一个参数并返回1和该参数之间所有数字的总和。C代码类似于:

unsigned int x = sumOf (7);
: :
unsigned int sumOf (unsigned int n) {
    unsigned int total = 0;
    while (n > 0) {
        total += n;
        n--;
    }
    return total;
}
为了调用这个函数,调用者将把7推到堆栈上,然后调用子例程。函数本身设置帧指针并为局部变量分配空间,因此您可以看到以下代码:

        mov  r1,7            ; fixed value
        push r1              ; push it for subroutine
        call sumOf           ; then call
retLoc: mov  [x],r1          ; move return value to variable
: :
sumOf:  mov  fp,sp           ; Set frame pointer to known location
        sub  sp,4            ; Allocate space for total.
: :
此时(在
子sp,4
之后),您有以下堆栈区域:

      +--------+
      | n(7)   |
      +--------+
      | retLoc |
      +--------+
fp -> | total  |
      +--------+
sp -> |        |
      +--------+
您可以看到,通过使用帧指针上方的地址和帧指针下方的局部变量,可以找到传入的参数

函数可以通过使用
[fp+8]
访问传入值(7),即
fp+8
处的内存内容(在本例中,每个单元格为四个字节)。它还可以使用
[fp-0]
访问自己的局部变量(
total
),即
fp-0
处的内存内容。我使用了
fp-0
命名法,尽管减去零没有效果,因为其他局部变量将具有相应的较低地址,如
fp-4
fp-8
等等


在堆栈上下移动时,帧指针也会移动,通常在调用函数之前将前一帧指针推到堆栈上,以便在离开该函数时轻松恢复。但是,尽管堆栈指针在函数中可能会剧烈移动,但帧指针通常保持不变,因此您可以始终找到相关变量。

帧指针指向当前帧中的内存区域(当前本地函数),通常它指向当前本地函数的返回地址。

因为还没有人对此做出响应,所以我将尝试一下。帧指针(如果内存可用)与堆栈指针一起是堆栈的一部分。堆栈由堆栈帧(有时称为激活记录)组成。堆栈指针指向堆栈顶部,而帧指针通常指向帧结构中的某个固定点,例如返回地址的位置。维基百科上有更详细的描述和图片

它就像是堆栈指针的更稳定版本 某些局部变量和参数的存储通常在堆栈帧中分配,只需在函数调用后将堆栈指针弹回到其原始级别,堆栈帧就会自动释放

但是,堆栈指针经常被调整,以便将参数推送到堆栈上以获得新的调用级别,并且在方法的入口上至少调整一次,以便分配它自己的局部变量。调整堆栈指针还有其他更模糊的原因

所有这些调整都使使用偏移量来获取参数、局部变量以及某些语言中的中间词法范围变得复杂。编译器跟踪可能不太难,但如果程序正在调试,那么调试器(人工或程序)也必须跟踪不断变化的偏移量

如果从技术上讲是不必要的开销,那么只分配一个寄存器指向当前帧就更简单了。在x86上,这是
%ebp
。进入函数时,它可能与堆栈指针有固定关系

除了调试之外,这还简化了异常管理,甚至可以通过消除或优化对堆栈指针的一些调整来为自己买单


您提到了程序计数器,因此值得注意的是,通常帧指针完全是一种软件构造,而不是硬件实现的东西,除非几乎每台机器都可以执行寄存器+偏移量寻址模式。有些机器(如x86)确实以寻址模式和宏指令的形式提供了一些硬件支持,用于创建和恢复帧。然而,有时会发现核心指令速度更快,宏操作最终被弃用。

Woh。。。堆栈指针?。。。这是程序计数器的同义词吗?不,堆栈指针(SP)与程序计数器(PC)绝不是同一寄存器:PC指向代码空间(指向“当前指令”或下一条指令,具体取决于CPU),SP始终指示“堆栈顶部”。哟