C++中如何打印调用栈

本文介绍了一种在C++程序中实现回溯调试的方法,通过使用backtrace函数记录调用堆栈信息,并配合编译选项-g和-rdynamic增强调试信息的可读性。此外,还提供了一个实用的宏定义,简化了回溯调试的过程。
  if (your_condition_bool_val == true)
  {
    void * array[10];
    char ** strings;
    size_t size = backtrace(array, 10);
    strings = backtrace_symbols(array, size);
    for (size_t i = 0; i < size; ++i)
    { 
      TBSYS_LOG(WARN, "backtrace%lu:[%s]", i, strings[i]);
    }
    free(strings);
  }


然后在Makefile中保证有下面两个编译选项:

CXXFLAGS = -g  -rdynamic

如果没有rdynamic,只会打印出调用者的地址,通过addr2line工具可以从地址反查到函数,不过这么做实在是太麻烦,还是加上编译选项更方便。

输出结果如下:

[2012-12-26 01:00:14.659541] WARN  init (ob_schema_service_impl.cpp:249) [1108461888] backtrace0:[/home/raywill/ob2/bin/rootserver(_ZN9oceanbase6common19ObSchemaServiceImpl4initEPNS0_12ObScanHelperEb+0x378) [0x5fa784]]
[2012-12-26 01:00:14.659552] WARN  init (ob_schema_service_impl.cpp:249) [1108461888] backtrace1:[/home/raywill/ob2/bin/rootserver(_ZN9oceanbase10rootserver13ObRootServer210get_schemaEbbRNS_6common17ObSchemaManagerV2ERl+0x4ab) [0x50716f]]
[2012-12-26 01:00:14.659558] WARN  init (ob_schema_service_impl.cpp:249) [1108461888] backtrace2:[/home/raywill/ob2/bin/rootserver(_ZN9oceanbase10rootserver14ObRootBalancer18nb_get_table_countEv+0x134) [0x4cfebc]]
[2012-12-26 01:00:14.659577] WARN  init (ob_schema_service_impl.cpp:249) [1108461888] backtrace3:[/home/raywill/ob2/bin/rootserver(_ZN9oceanbase10rootserver14ObRootBalancer14do_new_balanceEv+0xdf) [0x4d0399]]
[2012-12-26 01:00:14.659582] WARN  init (ob_schema_service_impl.cpp:249) [1108461888] backtrace4:[/home/raywill/ob2/bin/rootserver(_ZN9oceanbase10rootserver14ObRootBalancer10do_balanceERb+0x115) [0x4d08b3]]
[2012-12-26 01:00:14.659586] WARN  init (ob_schema_service_impl.cpp:249) [1108461888] backtrace5:[/home/raywill/ob2/bin/rootserver(_ZN9oceanbase10rootserver22ObRootBalancerRunnable3runEPN5tbsys7CThreadEPv+0x180) [0x4d265a]]
[2012-12-26 01:00:14.659591] WARN  init (ob_schema_service_impl.cpp:249) [1108461888] backtrace6:[/home/raywill/ob2/bin/rootserver(_ZN5tbsys7CThread4hookEPv+0x64) [0x69d134]]
[2012-12-26 01:00:14.659599] WARN  init (ob_schema_service_impl.cpp:249) [1108461888] backtrace7:[/lib64/libpthread.so.0 [0x3cf70064a7]]
[2012-12-26 01:00:14.659604] WARN  init (ob_schema_service_impl.cpp:249) [1108461888] backtrace8:[/lib64/libc.so.6(clone+0x6d) [0x33950d3c2d]]

@leekayak  写了一个宏,更加好用!


#define BACKTRACE(LEVEL, cond, _fmt_, args...) \
  do \
  { \
    if (cond) \
    { \
      void *buffer[100]; \
      int size = backtrace(buffer, 100); \
      char **strings = backtrace_symbols(buffer, size); \
      if (NULL != strings) \
      { \
        TBSYS_LOG(LEVEL, _fmt_ " BackTrace Start: ", ##args); \
        for (int i = 0; i < size; i++) \
        { \
          TBSYS_LOG(LEVEL, "BT[%d] @[%s]", i, strings[i]); \
        } \
        free(strings); \
      } \
    } \
  } while (false)


用法:
BACKTRACE(INFO, c1==c2, "%s, %d, %d. here is trace:",  "found c1 equals to c2", c1, c2);  //当c1==c2时打印backtrace

BACKTRACE(INFO, true, "here is trace:"); //总是打印backtrace

【搞定】


附:

addr2line用法: addr2line --exe=my_app 0x111111 0x2222222 0x3333333 


<think>根据用户的问题和提供的引用内容,用户想了解在C++打印调用栈的方法。引用中提供了几种不同的方法,包括Android平台特定方法和非Android平台(使用Boost库)的方法。 用户特别询问的是C++打印调用栈的方法,因此需要从引用中提取相关信息,并组织成清晰的回答。注意区分不同平台(Android和非Android)的方法,同时确保LaTeX格式正确。 引用[2]提供了Android C++打印调用栈的方法,使用Android特定的CallStack类。 引用[3]提供了一个非Android平台的方法,使用Boost.Stacktrace库。 另外,引用[1]是关于Java层的,引用[4]是关于fork的,与问题不直接相关,可以忽略。 因此,回答应分为两部分:Android C++方法和非Android C++方法(使用Boost)。 同时,按照要求,在回答末尾生成相关问题。 注意:在回答中,代码块应使用markdown格式,并且独立成行。行内数学表达式用$...$,但在这个问题中可能不涉及数学表达式,所以主要关注代码展示。 回答结构: 1. 介绍打印调用栈的作用(可选,简短说明)。 2. Android平台下的C++方法(引用[2])。 3. 非Android平台下的C++方法(引用[3])。 4. 生成相关问题。 注意:引用标识要放在相关内容的末尾,如[^2]。 </think> ### C++ 打印调用栈的方法 在 C++打印调用栈可帮助开发者定位代码执行路径和调试异常。以下是两种常用方法: #### 1. **Android 平台(C++层)** 使用 Android 系统提供的 `CallStack` 工具(需链接 Android NDK 库): ```cpp #include <utils/Log.h> #include <utils/CallStack.h> void dumping_callstack() { android::CallStack stack; // 若在非 android 命名空间,需加命名空间限定 stack.update(); // 捕获当前调用栈 stack.dump(1); // 输出到标准输出 stack.log("TAG"); // 输出到 logcat,参数为日志标签 } void test_func() { dumping_callstack(); // 在需要处调用 } ``` **说明**: - 需包含 Android NDK 头文件及链接 `libutils.so` - `dump()` 输出到 `printf`,`log()` 输出到 logcat #### 2. **通用平台(Linux/Unix)** 使用跨平台的 **Boost.Stacktrace** 库: ```cpp #include <iostream> #define BOOST_STACKTRACE_USE_ADDR2LINE #include <boost/stacktrace.hpp> void trace_function() { std::cout << boost::stacktrace::stacktrace() << std::endl; // 打印调用栈 } int main() { trace_function(); // 调用示例 } ``` **编译与依赖**: ```bash sudo apt install libboost-stacktrace-dev # 安装依赖 g++ -fno-pie -ggdb3 -O0 -o demo.cpp -std=c++11 -ldl ``` **说明**: - `BOOST_STACKTRACE_USE_ADDR2LINE` 确保输出包含符号名(需安装 `addr2line` 工具) - 输出示例: ``` 0# trace_function() 1# main 2# __libc_start_main ```[^3] --- ### 关键区别 | **方法** | 适用场景 | 依赖项 | |------------------|-------------------|------------------------| | Android CallStack | Android NDK 开发 | Android 系统库 | | Boost.Stacktrace | 跨平台 C++ 项目 | Boost 库, addr2line | > **注意**:在涉及 `fork()` 的子进程中打印调用栈时,需注意写时复制(Copy-on-Write)机制可能导致栈信息不完整[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值