博客
关于我
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/

    你可能感兴趣的文章
    Numpy.ndarray对象不可调用
    查看>>
    Numpy.VisibleDeproationWarning:从不整齐的嵌套序列创建ndarray
    查看>>
    Numpy:按多个条件过滤行?
    查看>>
    Numpy:条件总和
    查看>>
    numpy、cv2等操作图片基本操作
    查看>>
    numpy中的argsort的用法
    查看>>
    NumPy中的精度:比较数字时的问题
    查看>>
    numpy判断对应位置是否相等,all、any的使用
    查看>>
    Numpy多项式.Polynomial.fit()给出的系数与多项式.Polyfit()不同
    查看>>
    Numpy如何使用np.umprod重写range函数中i的python
    查看>>
    numpy学习笔记3-array切片
    查看>>
    numpy数组替换其中的值(如1替换为255)
    查看>>
    numpy数组索引-ChatGPT4o作答
    查看>>
    NUMPY矢量化np.prod不能构造具有超过32个操作数的ufunc
    查看>>
    Numpy矩阵与通用函数
    查看>>
    numpy绘制热力图
    查看>>
    numpy转PIL 报错TypeError: Cannot handle this data type
    查看>>
    Numpy闯关100题,我闯了95关,你呢?
    查看>>
    nump模块
    查看>>
    Nutch + solr 这个配合不错哦
    查看>>