Rust 中如何获取当前堆栈帧深度?

Jam*_*979 2 rust

如何确定当前堆栈帧深度?

fn print_depths() {
    println!("stack frame depth {}", stack_frame_depth());
    fn print_depth2() {
        println!("stack frame depth {}", stack_frame_depth());
    }
    print_depth2();
}

pub fn main() {
    print_depths();
}
Run Code Online (Sandbox Code Playgroud)

会打印

stack frame depth 1
stack frame depth 2
Run Code Online (Sandbox Code Playgroud)

我知道main有来电者,所以具体号码可能会有所不同。


我努力了stacker::remaining_stack。但是,这会打印堆栈中剩余的字节数。由于传递给函数的参数会影响堆栈字节“高度”,因此不可能派生出简单的函数调用“高度”。我想要当前函数调用高度的计数。

Pet*_*all 6

优化后,实际运行的代码不太可能与您最初编写的函数结构有任何相似之处。

如果 Rust 公开一个函数来提供堆栈上的调用帧数量,则该数量将有很大差异,具体取决于优化设置和这些函数的确切内容。例如,添加调试打印语句是否内联可能会发生变化。该数字可能会有所不同,具体取决于构建是调试还是发布、是否启用 lto 或者甚至是否升级到较新的编译器。

为了准确跟踪与源代码中的函数相对应的函数调用数量,编译器需要为每个函数体添加一个计数器增量,这打破了 Rust 零成本抽象的承诺。

您可以编写一个用于声明函数的宏,该宏在每个函数开始时递增计数器并在结束时递减。然后你就为你使用的东西付费。例如,是一个简化的(不支持泛型)声明性宏,它可以执行此操作。对于这样的事情,程序宏会更好,您可以将其定义为属性来调用。


egg*_*yal 6

如果在注意到Peter Hall 的答案中的所有警告后,仍然需要获得实际的堆栈深度,请考虑backtrace::Backtrace

#[inline]
fn stack_frame_depth() -> usize {
    Backtrace::new_unresolved().frames().len()
}
Run Code Online (Sandbox Code Playgroud)

在操场上看到它

如果您想避免实例化 a 所涉及的分配Backtrace,请考虑backtrace::trace

#[inline]
fn stack_frame_depth() -> usize {
    let mut depth = 0;
    backtrace::trace(|_| {
        depth += 1;
        true
    });
    depth
}
Run Code Online (Sandbox Code Playgroud)

然而,上述两种方法都需要std线程安全。如果您的板条箱是no_std和/或您正在以其他方式确保同步,那么backtrace::trace_unsynchronized.