博客
关于我
C++封装一个易用的打印backtrace信息的函数
阅读量:733 次
发布时间:2019-03-21

本文共 2567 字,大约阅读时间需要 8 分钟。

如何通过C++编写一个易于使用的打印堆栈信息函数

  • 堆栈信息追踪的重要性

    在调试程序过程中,当遇到错误时,能够快速获取当前函数调用堆栈信息至关重要。通常,这会在调用assert函数之前进行,以便定位问题所在。

  • 查看所需的核心函数

  • 2.1 backtrace函数

    backtrace函数的原型为:

    int backtrace(void **buffer, int size);

    使用说明:

    该函数会将当前程序的堆栈信息写入buffer数组。每个数组元素是返回地址,信息是倒序存储的(最近调用在前,遥远调用在后)。通过确保buffer大小和容量足够,可以获取完整的堆栈日志。返回值表示实际获取到的堆栈信息数量,数值不会超过size

    2.2 backtrace_symbols函数

    backtrace_symbols函数的原型为:

    char **backtrace_symbols(void *const *buffer, int size);

    使用说明:

    该函数接受backtrace返回的地址数组,将其转换为字符串数组。每个字符串包含函数名(如果确定可知)、十六进制偏移量和实际返回地址。返回值是一个指针,指向新的字符串数组。注意,这个数组的内存必须由调用者释放,但字符串内容不需要处理。

    2.3 __cxa_demangle函数

    __cxa_demangle函数的原型为:

    char* __cxa_demangle(const char *mangled_name, char *output_buffer, size_t *length, int *status);

    使用说明:

    这个C++内联函数反转编译器添加的符号信息,将其转换为原始函数名。主要作用是解析 και符号sequences。调用者应提供被编译后的符号字符串,并处理返回结果,注意释放动态分配的内存。

    1. 测试各函数的实际使用情况
    2. 3.1 调用backtrace获取日志

      举例:

      void fun(){      static int count = 0;      if (++count == 5){          Backtrace(50, 0);          return;      }      fun();  }  int main(int argc, char* argv[]){      fun();      return 0;  }

      运行后,期望输出包含5次fun调用的堆栈信息。

      3.2 转换为符号名称

      调用backtrace_symbols后,输出应类似于:

      ./all(_Z9BacktraceiiRKSs+0x58) [0x401c43]./all(_Z3funv+0x48)...

      需要提取括号内的名称并解析。

      3.3 使用__cxa_demangle获取原始函数名

      最终结果应类似于:

      Backtrace(int, int, std::string const&).fun()fun()fun()fun()fun()./all(main+0x9)...

      结果表明,其中Backtrace被调用5次,遵循预期调用次数。

      1. 完整代码示例
      2. #include 
        #include
        #include
        #include
        #include
        #include
        #include
        #include
        namespace detail { std::string demangle(const char* str) { size_t size = 0; int status = 0; std::string sstr; sstr.resize(256); if (1 == sscanf(str, "%*[^(]%*[^_]%255[^)+]", &sstr[0])) { char* tmp = abi::__cxa_demangle(&sstr[0], nullptr, &size, &status); if (tmp) { std::string result(tmp); free(tmp); return result; } } if (1 == sscanf(str, "%255s", &sstr[0])) return sstr; return str; } std::string Backtrace(int size = 64, int skip = 2, const std::string& prefix = "") { void* array[size]; size_t s = backtrace(array, size); char** str = backtrace_symbols(array, s); std::vector
        bt; std::stringstream ss; if (str) { for (size_t i = skip; i < s; ++i) { bt.push_back(demangle(str[i])); } free(str); } else { ss << "backtrace_symbols failed"; goto good; } for (const auto& b : bt) { ss << prefix << b << "\n"; }good: return ss.str(); } void fun() { static int count = 0; if (++count == 5) { Backtrace(50, 0); return; } fun(); } int main(int argc, char* argv[]) { fun(); return 0; }}

        以上代码展示了一个完整的解决方案,包括函数定义、调试工具的使用和示例测试程序。通过这种方法,可以方便地获取和解析堆栈信息,使调试过程更加高效。

    转载地址:http://wxsgz.baihongyu.com/

    你可能感兴趣的文章
    Pandas 读取具有浮点值的 csv 文件会导致奇怪的舍入和小数位数
    查看>>
    pandas 适用,但仅适用于满足条件的行
    查看>>
    pandas 重新采样到每月的特定工作日
    查看>>
    pandas :按移位分组和累加和(GroupBy Shift And Cumulative Sum)
    查看>>
    pandas :检测一个DF和另一个DF之间缺失的列
    查看>>
    Pandas-从具有嵌套列表列表的现有列创建动态列时出错
    查看>>
    Pandas-通过对列和索引的值求和来合并两个数据框
    查看>>
    pandas.read_csv()的详解-ChatGPT4o作答
    查看>>
    PANDAS.READ_EXCEL()输出‘;溢出错误:日期值超出范围‘;而不存在日期列
    查看>>
    Pandas:对给定列求和 DataFrame 行
    查看>>
    Pandas、Matplotlib、Pyecharts数据分析实践
    查看>>
    Pandas中文官档~基础用法2
    查看>>
    Pandas中文官档~基础用法6
    查看>>
    pandas交换两列
    查看>>
    pandas实战:电商平台用户分析
    查看>>
    pandas打乱数据的顺序
    查看>>
    pandas改变一列值(通过apply)
    查看>>
    Pandas数据分析的环境准备
    查看>>
    Pandas数据可视化怎么做?用实战案例告诉你!
    查看>>
    Pandas数据处理与分析教程:从基础到实战
    查看>>