基于 C++20 的 std::source_location 和宏实现侵入式的函数调用栈追踪。

mtracer.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#pragma once

#include <algorithm>
#include <cstddef>
#include <source_location>
#include <stack>
#include <string>

class MTracer {
public:
// NOLINTNEXTLINE(fuchsia-default-arguments-declarations)
explicit MTracer(const std::source_location &location =
std::source_location::current()) {
get_stack().push(location);
}

~MTracer() { get_stack().pop(); }

MTracer &operator=(const MTracer &) = delete;
MTracer(const MTracer &) = delete;

[[nodiscard]] static std::string dump_string() {
std::stack<std::source_location> tracer_stack(get_stack());

std::string str_result = "\nCall stack (MTRACER):";

std::size_t i = tracer_stack.size();
while (!tracer_stack.empty()) {
std::string str_tmp = '\n' + std::to_string(i - 1) + ": "
+ format(tracer_stack.top());
std::ranges::replace(str_tmp, '\\', '/');
str_result += str_tmp;
tracer_stack.pop();
--i;
}

return str_result + '\n';
}

static std::string format(const std::source_location &location) {
return std::string{location.file_name()} + ":"
+ std::to_string(location.line()) + " "
+ location.function_name();
}

private:
static std::stack<std::source_location> &get_stack() {
static std::stack<std::source_location> m_tracer_stack;
return m_tracer_stack;
}
};

#ifdef USE_MTRACER

#define MTRACER_CB_INNER(a, b) a##b
#define MTRACER_CB(a, b) MTRACER_CB_INNER(a, b)

#define MTRACER MTracer MTRACER_CB(tmp_tracer_, __LINE__)
#define MTRACER_DUMP_STRING MTracer::dump_string()
#define MTRACER_DUMP \
do { std::cerr << MTracer::dump_string(); } while (false)

#else

#define MTRACER ((void)0)
#define MTRACER_DUMP_STRING \
std::string("\nMTracer: Define USE_MTRACER to use MTracer.\n")
#define MTRACER_DUMP ((void)0)

#endif

测试代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#define USE_MTRACER

#include "mtracer.hpp"
#include <iostream>

class A {
public:
static void Fun() {
MTRACER;
std::cerr << MTRACER_DUMP_STRING;
}

static void Fun2() {
MTRACER;

[[maybe_unused]] double value = [](double max_value) {
double s = 0;
int n = 1;
while (s < max_value) {
s += (1.0 / n);
++n;
}
return s;
}(20);

Fun();
}

static void Fun3() {
MTRACER;

[[maybe_unused]] double value = [](double max_value) {
double s = 0;
int n = 1;
while (s < max_value) {
s += (1.0 / n);
++n;
}
return s;
}(40);

Fun2();
}
};

int main() {
MTRACER;

A::Fun3();

return 0;
}

运行结果如下

1
2
3
4
5
6

Call stack (MTRACER):
3: .../mtracer_demo.cpp:9 static void A::Fun()
2: .../mtracer_demo.cpp:14 static void A::Fun2()
1: .../mtracer_demo.cpp:30 static void A::Fun3()
0: .../mtracer_demo.cpp:47 int main()