【问题标题】:Print stack in C++C++ 中的打印堆栈
【发布时间】:2020-08-28 08:42:27
【问题描述】:

考虑以下代码:

#include <iostream>

void overflower(const int *startAddress)
{
    int j = 0;  
    std::cout << uintptr_t(&j) - uintptr_t(startAddress) 
    << ": stack bottom : " << startAddress << ", current : " << &j <<'\n';
    overflower(&j);
}

int main()
{
    const int i = 0;
    const int* startAddress = &i;

    std::cout << uintptr_t(&i) - uintptr_t(startAddress)   
    << ": stack bottom : " << startAddress << ", current : " << &i <<'\n';

    overflower(&i);
}

我希望它输出堆栈的 startAddress 和 currentAddress 之间的差异。

但是由于某种原因,随着堆栈的增长,startAddress 似乎也增加了。

我得到这样的输出:

18446744073709551568: stack bottom : 0x7ffddc752254, current : 0x7ffddc752224
18446744073709551568: stack bottom : 0x7ffddc752224, current : 0x7ffddc7521f4
18446744073709551568: stack bottom : 0x7ffddc7521f4, current : 0x7ffddc7521c4
18446744073709551568: stack bottom : 0x7ffddc7521c4, current : 0x7ffddc752194
18446744073709551568: stack bottom : 0x7ffddc752194, current : 0x7ffddc752164
18446744073709551568: stack bottom : 0x7ffddc752164, current : 0x7ffddc752134

简而言之。为什么 startAddress 被修改而不是保持不变?

【问题讨论】:

  • 因为您使用当前调用的j 变量的地址调用overflower。你的意思是打电话给overflower(startAddress) 吗?
  • 另外,堆栈很可能在您的平台上增长,所以j - startAddress 是负数,当解释为uintptr_t 时,这是一个非常大的数字。
  • 方向似乎没问题。是的,overflower 应该调用 startAddress。这些错误之一是愚蠢的发现......

标签: c++


【解决方案1】:

就像 cmets 中建议的那样。

应该是

overflower(startAddress);

比我们得到的输出:

174505: stack bottom : 0x7ffda8a3e814, current : 0x7ffda8241844
174506: stack bottom : 0x7ffda8a3e814, current : 0x7ffda8241814
174507: stack bottom : 0x7ffda8a3e814, current : 0x7ffda82417e4
174508: stack bottom : 0x7ffda8a3e814, current : 0x7ffda82417b4
174509: stack bottom : 0x7ffda8a3e814, current : 0x7ffda8241784
174510: stack bottom : 0x7ffda8a3e814, current : 0x7ffda8241754
Segmentation fault

并且可以在分段错误之前看到堆栈的大小。

【讨论】:

    【解决方案2】:

    当您这样做时,您的代码会调用未定义的行为

    uintptr_t(&j) - uintptr_t(startAddress) 
    

    因为它计算不相关的变量地址之间的差异(不在同一个数组或类/结构中)。

    【讨论】:

    • uintptr_t 是无符号整数类型,因此对其进行算术运算是完全有效的。
    • 问题不在于算术,而是指向不在同一个数组中的对象的指针的比较。无法保证记忆中的距离是有意义的
    • 我以为它们都在堆栈上,我们在这里打印堆栈差异
    • @PaulMcKenzie 我不明白未定义行为的来源。我们将 2 个指针转换为 uintptr_ts ,它的定义非常明确。然后对定义明确的两个无符号整数值进行一些数学运算。当然,对数学结果的分析可能是错误的,但这里没有什么是严格未定义的。由于 undefined behavoir 在 C++ 中具有严格的含义,我认为这不属于,还是我错了?
    • @Jeffrey "undefined behavoir" 在 C++ 中有严格的含义。而那个意思肯定是not“不保证有意义”。如果我理解正确的话,这里没有什么是未定义的行为。
    猜你喜欢
    • 2017-08-15
    • 2016-04-11
    • 1970-01-01
    • 2010-09-08
    • 2014-12-29
    • 1970-01-01
    • 2010-09-23
    • 2021-04-06
    • 2012-08-23
    相关资源
    最近更新 更多