V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
mjy2
V2EX  ›  问与答

C++ 如何在当前函数内 知道是哪个函数调用了当前函数

  •  
  •   mjy2 · 2022-05-31 16:49:42 +08:00 · 1144 次点击
    这是一个创建于 667 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在实习中,遇到了一些问题。问下有没有大佬帮忙解答一下~ 有个触发器被指针 A 与 B 注册为回调函数,我要在触发器函数内查看是 A 调用了还是 B 调用了该触发器。 如果不添加额外的引用参数(自研引擎,不好改),该怎么实现呢?

    4 条回复    2022-05-31 18:10:57 +08:00
    Donahue
        1
    Donahue  
       2022-05-31 17:05:54 +08:00
    https://stackoverflow.com/questions/3899870/print-call-stack-in-c-or-c
    找到了一些可能有用的信息~

    google 关键字 c++ call stack
    mjy2
        3
    mjy2  
    OP
       2022-05-31 18:06:45 +08:00
    @Donahue 看了下是返回内存地址,那么每次运行的话,得出的内存地址都会不同嘛
    anonymous256
        4
    anonymous256  
       2022-05-31 18:10:57 +08:00
    在你的触发器函数里面,解开函数调用栈就可以了。三种常用的办法:

    1. gcc 内置宏__builtin_return_address:非常粗略的低级方法。这会在堆栈上的每一帧上获得函数的返回地址。注意:只是地址,不是函数名。所以需要额外的处理来获取函数名。
    2. glibc 的 backtrace 和 backtrace_symbols:可以获取调用堆栈上函数的实际符号名称。
    3. libunwind 库

    参考自: https://eli.thegreenplace.net/2015/programmatic-access-to-the-call-stack-in-c/

    根据上述文章提到的办法,采用 libunwind 库,我简单修改了下它的代码:
    1. 代码示例

    ```
    // example.cpp

    #include <libunwind.h>
    #include <stdio.h>

    // Call this function to get a backtrace.
    void backtrace() {
    unw_cursor_t cursor;
    unw_context_t context;

    // Initialize cursor to current frame for local unwinding.
    unw_getcontext(&context);
    unw_init_local(&cursor, &context);

    // Unwind frames one by one, going up the frame stack.
    while (unw_step(&cursor) > 0) {
    unw_word_t offset, pc;
    unw_get_reg(&cursor, UNW_REG_IP, &pc);
    if (pc == 0) {
    break;
    }
    printf("0x%lx:", pc);

    char sym[256];
    if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0) {
    printf("(caller function: %s+, offset: 0x%lx)\n", sym, offset);
    } else {
    printf(" -- error: unable to obtain symbol name for this frame\n");
    }
    }
    }

    void foo1() {
    backtrace(); // <-------- backtrace here!
    }

    void foo2() {
    backtrace(); // <-------- backtrace here!
    }


    int main(int argc, char **argv) {
    foo1(); // <-----在函数 foo1()和 foo2()中可以看到整个的调用栈。
    printf("\n");
    foo2();
    return 0;
    }

    ````

    2. 编译前安装依赖(以 ubuntu 为例):
    sudo apt install libunwind-dev

    3. 编译指令:
    g++ -o example example.cpp -L /usr/local/lib -lunwind
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   4031 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 00:58 · PVG 08:58 · LAX 17:58 · JFK 20:58
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.