【问题标题】:how to find stack is increasing or decreasing in C?如何在C中找到堆栈正在增加或减少?
【发布时间】:2011-06-26 10:29:14
【问题描述】:

使用 C 程序增加或减少堆栈?

【问题讨论】:

标签: c stack


【解决方案1】:

是的,在 C 中,函数范围内的变量通常是通过堆栈来实现的。但是这个模型不是由 C 标准强加的,编译器可以以任何它喜欢的方式实现这一点。标准中甚至没有提到“堆栈”这个词,如果它在或减少的话,甚至更少。您永远不应该尝试对此进行假设。

【讨论】:

    【解决方案2】:

    错误的二分法。除了增减之外,还有很多选择,其中一个就是每次函数调用都执行malloc的等价,为被调用者的自动存储获取内存,调用被调用者,返回后执行free的等价.更复杂的版本将一次分配大量的“堆栈”,并且仅在即将耗尽时分配更多。

    我会在具有虚拟内存的现代机器上调用这两种非常糟糕的设计,但在没有 MMU 的微处理器上实现多进程操作系统时它们可能是有意义的,因为在每个进程中为堆栈保留一定范围的内存会浪费大量的地址空间。

    【讨论】:

      【解决方案3】:

      怎么样:

      int stack_direction(void *pointer_to_local)
      {
           int other_local;
      
           return (&other_local > pointer_to_local) ? 1 : -1;
      }
      
      ...
      int local;
      printf("direction: %i", stack_direction(&local);
      

      因此,您将调用堆栈上某个位置的变量地址与外部位置的变量地址进行比较。

      【讨论】:

      • 为安全起见,应关闭编译器优化,以免内联。
      • "&other_local > pointer_to_local" 导致未定义的行为。
      • @sigjuice 如其他地方所述,C 是否甚至使用堆栈都没有定义。如果作者愿意假设一个堆栈并对方向做出最佳猜测,那么我认为这是最好的猜测代码。所有这些我本来应该在答案中说出来。
      【解决方案4】:

      如果您只想知道堆栈是否已更改,您可以将最后插入的对象保留在堆栈中,查看它的顶部并比较两者。

      【讨论】:

        【解决方案5】:

        编辑

        阅读 cmets。使用我的方法似乎无法确定堆栈方向。

        结束编辑

        在栈上声明一个数组变量,比较连续元素的地址。

        #include <stdio.h>
        #include <stdlib.h>
        int
        main(void)
        {
            char buf[16];
            printf("&buf[0]: %x\n&buf[1]: %x\n", &buf[0], &buf[1]);  
            return 0;
        }
        

        输出是:

        misha@misha-K42Jr:~/Desktop/stackoverflow$ ./a.out 
        &buf[0]: d1149980
        &buf[1]: d1149981
        

        正如预期的那样,堆栈正在向下增长。

        【讨论】:

        • 变量可能会被编译器重新排序,所以比较一个函数和嵌套函数的堆栈变量会更好一些。
        • 您说得有道理,但编译器会重新排列数组中的元素吗?我不这么认为。
        • 指针算法要求数组中的元素一个接一个。如果你声明一个 16 字节的数组,那要么将 16 个字节添加到堆栈指针,要么减去它们,但数组仍将从一个位置开始并向上到达其末尾。
        • 编译器仍然可以让堆栈在一个方向上增长,并让数组元素以另一种方式索引。我不明白为什么一个暗示另一个。
        • @Jens Gustedt:那么有没有办法做到这一点?您可以尝试使用 @Vlad 建议的嵌套函数,但编译器可以内联该函数并重新排序变量。
        【解决方案6】:

        您还可以使用内联汇编监控 ESP 寄存器。 ESP 寄存器保存未分配堆栈的地址。因此,如果将某些东西推入堆栈 - ESP 会减少,如果弹出 - ESP 会增加。 (还有其他修改堆栈的命令,例如函数调用/返回)。

        例如,当我们尝试计算诸如斐波那契数(Visual Studio)之类的递归函数时,堆栈发生了什么:

        #include <stdio.h>
        
        int FibonacciNumber(int n) {
            int stackpointer = 0;
            __asm {
                mov stackpointer, esp
            }
            printf("stack pointer: %i\n", stackpointer);
        
            if (n < 2)
                return n;
            else
                return FibonacciNumber(n-1) + FibonacciNumber(n-2);
        }
        
        int main () {
            FibonacciNumber(10);
            return 0;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-03-02
          • 2020-09-19
          • 2012-04-18
          • 2011-04-13
          • 2015-08-14
          • 2013-07-26
          • 1970-01-01
          相关资源
          最近更新 更多