C++ 代码点跟踪
一种临时解决方案,用于标记和跟踪 C++ 中的代码点
引言
虽然不应该出现这种情况,但有时很难确定程序执行过程中运行了哪些代码点。 市面上有很多专业的工具,从静态分析到仪器测量,可以回答这些问题,但在某些情况下,临时解决方案可能更有效。
背景
实现此方法是利用静态变量在程序启动前的初始化,但由于所有代码点都在函数中,因此“静态锚点”必须以某种方式放置在那里,因此需要克服 C++ 的 函数级静态变量延迟初始化 特性。
这可以通过模板类 (X
) 添加一个间接引用,并带有 static
成员变量 (progloc_
) 来强制每个模板参数的初始化,而该模板参数又是一个包装 struct
,用于传输所需的信息 (_FILE._ “在第” _.LINE._ 行)。将这些组合在一起,实现此目标的最重要代码可能如下所示
template <class T> class X {
public:
static T progloc_;
};
template <class T> T X<T>::progloc_;
#define TRACE_CODE_POINT { \
struct ProgLocation { \
public: \
std::string loc_; \
ProgLocation() : loc_(std::string(__FILE__ " at line " S__LINE__)) \
{ \
TestFw::CodePoints::Test::imHere(loc_); \
} \
}; \
TestFw::CodePoints::X<ProgLocation> dummy; \
TestFw::CodePoints::Test::iGotCalled(dummy.progloc_.loc_); }
ProgLocation
- 构造函数中使用的 S_._LINE_._
技巧来自 Stack Overflow 上的这里。
#define S(x) #x
#define S_(x) S(x)
#define S__LINE__ S_(__LINE__)
要跟踪,可以使用以下方法
class Test
{
private:
typedef std::set<std::string> TFuncs;
static TFuncs registeredFunctions;
static TFuncs calledFunctions;
public:
static int imHere(const std::string fileAndLine)
{
assert(registeredFunctions.find(fileAndLine) == registeredFunctions.end());
registeredFunctions.insert(fileAndLine);
return 0;
}
static void iGotCalled(const std::string fileAndLine)
{
if (calledFunctions.find(fileAndLine) == calledFunctions.end())
calledFunctions.insert(fileAndLine);
}
static void report()
{
for (TFuncs::const_iterator rfIt = registeredFunctions.begin();
rfIt != registeredFunctions.end(); ++rfIt)
if (calledFunctions.find(*rfIt) == calledFunctions.end())
std::cout << (*rfIt) << " didn't get called" << std::endl;
}
};
Using the Code
跟踪代码点所需的全部内容是在所需位置放置宏
TRACE_CODE_POINT
并在程序结束时调用 Test
类的 report()
方法。
关注点
提供的解决方案由于多种原因非常 危险,应谨慎使用。 未考虑性能或线程安全性。 到目前为止,该代码仅在 MSVC 2010 和 2013 上进行了测试。
如果您打算使用该代码,您可能还需要考虑向报告方法添加一些分派。 在提示开始时提供的 zip 文件中的示例源代码包含一个这样的报告器,以及一个控制台和一个调试输出窗口接收器,还有一个方便的助手来构建主函数。
历史
- 2013/12/20:首次发布