backtrace函数的使用

backtrace()是glibc(>=2.1)提供的函数,用于跟踪函数的调用关系。

以下对backtrace()函数的说明以及实例,都来自其man page。


函数定义
       #include <execinfo.h>

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

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

       void backtrace_symbols_fd(void *const *buffer, int size, int fd);

函数说明

backtrace()函数用来获取程序中当前函数的回溯信息,即一系列的函数调用关系,获取到的信息被放在参数buffer中。buffer是一个数组指针,数组的每个元素保存着每一级被调用函数的返回地址。参数size指定了buffer中可存放的返回地址的数量。如果函数实际的回溯层级数大于size,则buffer中只能存放最近的函数调用关系,所以,想要得到完整的回溯信息,就要确保size参数足够大。
backtrace()函数的返回值为buffer中的条目数量,这个值不一定等于size,因为如果为得到完整回溯信息而将size设置的足够大,则该函数的返回值为buffer中实际得到的返回地址数量。
  
通过backtrace()函数得到buffer之后,backtrace_symbols()可以将其中的返回地址都对应到具体的函数名,参数size为buffer中的条目数。backtrace_symbols()函数可以将每一个返回值都翻译成“函数名+函数内偏移量+函数返回值”,这样就可以更直观的获得函数的调用关系。
经过翻译后的函数回溯信息放到backtrace_symbols()的返回值中,如果失败则返回NULL。需要注意,返回值本身是在backtrace_symbols()函数内部进行malloc的,所以必须在后续显式地free掉。
  
backtrace_symbols_fd()的buffer和size参数和backtrace_symbols()函数相同,只是它翻译后的函数回溯信息不是放到返回值中,而是一行一行的放到文件描述符fd对应的文件中。

注意,在编译的时候需要加上-rdynamic选项让链接器将所有符号添加到动态符号表中,这样才能将函数地址翻译成函数名。另外,这个选项不会处理static函数,所以,static函数的符号无法得到。

示例:

#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void
myfunc3(void)
{
   int j, nptrs;
#define SIZE 100
   void *buffer[100];
   char **strings;

   nptrs = backtrace(buffer, SIZE);
   printf("backtrace() returned %d addresses\n", nptrs);

   /* The call backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO)
	  would produce similar output to the following: */

   strings = backtrace_symbols(buffer, nptrs);
   if (strings == NULL) {
	   perror("backtrace_symbols");
	   exit(EXIT_FAILURE);
   }

   for (j = 0; j < nptrs; j++)
	   printf("%s\n", strings[j]);

   free(strings);
}

static void   /* "static" means don't export the symbol... */
myfunc2(void)
{
   myfunc3();
}

void
myfunc(int ncalls)
{
   if (ncalls > 1)
	   myfunc(ncalls - 1);
   else
	   myfunc2();
}

int
main(int argc, char *argv[])
{
   if (argc != 2) {
	   fprintf(stderr, "%s num-calls\n", argv[0]);
	   exit(EXIT_FAILURE);
   }

   myfunc(atoi(argv[1]));
   exit(EXIT_SUCCESS);
}

进行编译:

cc -rdynamic prog.c -o prog

代码运行结果为:

$ ./prog 3
           backtrace() returned 8 addresses
           ./prog(myfunc3+0x5c) [0x80487f0]
           ./prog [0x8048871]
           ./prog(myfunc+0x21) [0x8048894]
           ./prog(myfunc+0x1a) [0x804888d]
           ./prog(myfunc+0x1a) [0x804888d]
           ./prog(main+0x65) [0x80488fb]
           /lib/libc.so.6(__libc_start_main+0xdc) [0xb7e38f9c]
           ./prog [0x8048711]



  • 8
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
回溯算法是一种通过穷举所有可能的解来求解问题的算法。它通常用于解组合优化问题,其中需要在给约束条件下找到最优解。01背包问题是一个经典的组合优化问题,它要求在给定背包容量和一组物品的重量和价值的情况下,选择一些物品放入背包中,使得背包中物品的总价值最大,同时不能超过背包的容量。 回溯算法解决01背包问题的基本思想是通过递归的方式遍历所有可能的解空间,并在搜索过程中进行剪枝,以提高搜索效率。具体步骤如下: 1. 定义一个递归函数backtrack,该函数接受当前背包容量、当前物品索引和当前背包中物品的总价值作为参数。 2. 在递归函数中,首先判断当前物品索引是否超过物品总数或者当前背包容量是否小于等于0,如果是,则返回当前背包中物品的总价值。 3. 如果不满足上述条件,则有两种情况: - 将当前物品放入背包中,更新背包容量和物品总价值,并递归调用backtrack函数。 - 不将当前物品放入背包中,直接递归调用backtrack函数。 4. 在递归调用后,比较两种情况的结果,返回较大的总价值作为当前背包中物品的最大总价值。 下面是一个使用回溯算法解决01背包问题的Python示例代码: ```python def backtrack(capacity, weights, values, index, total_value): if index >= len(weights) or capacity <= 0: return total_value # 将当前物品放入背包中 if capacity >= weights[index]: total_value1 = backtrack(capacity - weights[index], weights, values, index + 1, total_value + values[index]) else: total_value1 = 0 # 不将当前物品放入背包中 total_value2 = backtrack(capacity, weights, values, index + 1, total_value) return max(total_value1, total_value2) # 示例数据 capacity = 10 weights = [2, 3, 4, 5] values = [3, 4, 5, 6] max_value = backtrack(capacity, weights, values, 0, 0) print("Max value: ", max_value) ``` 这段代码中,我们定义了一个backtrack函数来求解01背包问题。在示例数据中,背包容量为10,物品的重量和价值分别为[2, 3, 4, 5]和[3, 4, 5, 6]。运行代码后,将输出最大总价值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值