我的测试文件很短:
let print_backtrace () = try raise Not_found with
Not_found -> Printexc.print_backtrace stdout;;
let f () = print_backtrace (); Printf.printf "this is to make f non-tail-recursive\n";;
f ();
我编译并运行:
% ocamlc -g test.ml
% OCAMLRUNPARAM=b ./a.out
Raised at file "test.ml", line 1, characters 35-44
this is to make f non-tail-recursive
为什么堆栈跟踪中没有列出f
?如何编写一个函数来打印它所调用位置的堆栈跟踪?
答案 0 :(得分:6)
Printexc.print_backtrace
的文档说:
回溯列出了引发最近引发的异常的程序位置以及通过函数调用传播的位置。
它实际上似乎正在做正确的事情。该异常尚未通过f传播回来。
如果我在Printexc.print_backtrace
的通话之外将通话移至f
,我会看到完整的回溯。
$ cat test2.ml
let print_backtrace () = raise Not_found
let f () = let res = print_backtrace () in res ;;
try f () with Not_found -> Printexc.print_backtrace stdout
$ /usr/local/ocaml312/bin/ocamlc -g test2.ml
$ OCAMLRUNPARAM=b a.out
Raised at file "test2.ml", line 1, characters 31-40
Called from file "test2.ml", line 3, characters 21-39
Called from file "test2.ml", line 5, characters 4-8
答案 1 :(得分:5)
这是执行我建议的代码。如果可能的话,我建议使用ocamldebug,这段代码太棘手了。但是对于这个简单的例子,它适用于我的系统。
let print_backtrace () =
match Unix.fork () with
| 0 -> raise Not_found
| pid -> let _ = Unix.waitpid [] pid in ()
let f () =
begin
print_backtrace ();
Printf.printf "after the backtrace\n";
end
;;
f ()
这是一次试运行。
$ /usr/local/ocaml312/bin/ocamlc unix.cma -g test3.ml
$ OCAMLRUNPARAM=b a.out
Fatal error: exception Not_found
Raised at file "test3.ml", line 3, characters 17-26
Called from file "test3.ml", line 8, characters 4-22
Called from file "test3.ml", line 14, characters 0-4
after the backtrace
我意识到由于未被捕获的异常,您实际上无法控制子进程的退出方式。这就是为什么这段代码太棘手了。如果它不适合你,请不要怪我,但我希望它确实有用。
我使用OCaml 3.12.0在Mac OS X 10.6.8上测试了代码。
致以最诚挚的问候,