65.9K
CodeProject 正在变化。 阅读更多。
Home

函数调用序列跟踪类

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.56/5 (12投票s)

2003年8月16日

2分钟阅读

viewsIcon

65665

downloadIcon

1147

一个用于跟踪函数调用顺序的类。

Sample image

引言

在复杂的应用程序中,有时需要处理大量的消息,并且有大量的函数用于处理请求和事件。有时很难看出给定函数调用了哪些函数,哪些函数会导致对特定函数的调用,以及所有这些函数的调用顺序。如果某个程序员要继续另一个程序员未完成的工作,那么在一个文档记录不完善的系统中,这将是一场噩梦。即使是之前完成所有这些工作的程序员也可能会感到困惑。我在我的一个项目中遇到了这个问题。我在互联网上搜索解决方案,但不幸的是,我没有找到,所以我开始自己做。我编写了一个类来跟踪应用程序中的方法,并将所有序列以可读的格式记录到一个文件中。

想法

我的解决方案的想法是使用一个小型类的全局对象,该类具有一些静态成员函数和静态成员变量。在应用程序的早期阶段(例如,在应用程序类的构造函数中),我们指定将保存序列日志的文件。这是通过一个静态函数完成的。该类包含一些私有静态成员变量来维护当前的调用级别。在函数开始时,使用构造函数在堆栈中实例化此类的实例,构造函数以应记录的文本作为参数。在函数结束时,此类的实例将超出范围,因此将调用该类的析构函数,并且级别将降低。

实现

以下是 SequenceTracer 类的头文件

// SequenceTracer.h

#ifndef _SEQUENCE_TRACER
#define _SEQUENCE_TRACER

#include <fstream>  // for std::ofstream


class SequenceTracer  
{
public:
    static void Start(const char * fileName); // Set the file name and start
    SequenceTracer(const char * text); // The only constructor
    virtual ~SequenceTracer();
protected:
    static int Stack[256]; // The stack maintaing sequence numbers
    static int Level; // The current level in the stack
    static std::ofstream * OutStream; // The always open output stream

};

#endif //_SEQUENCE_TRACER

这是该类的实现文件

// SequenceTracer.cpp

#include "SequenceTracer.h"
//////////////////////////////////////////////////////////////////////
int SequenceTracer::Level;
std::ofstream * SequenceTracer::OutStream;
int SequenceTracer::Stack[256];
//////////////////////////////////////////////////////////////////////
void SequenceTracer::Start(const char *fileName)
{
    OutStream = new std::ofstream (fileName);
}
//////////////////////////////////////////////////////////////////////
SequenceTracer::SequenceTracer(const char * text)
{
    if (!OutStream) // Outstream should be initialized
        return;

    for (int i = 0; i < Level; i++)
        *OutStream << '\t'; // Make indentation

    Stack[Level]++; // Increment the sequence number

    for (i = 0; i < Level, Stack[i] > 0; i++)
        *OutStream << Stack[i] << '.'; // Print the sequence number

    *OutStream << " "; // Add a space
    *OutStream << text << "\n"; // Write the text followed by newline
    Level++; // Increase the level
}
//////////////////////////////////////////////////////////////////////
SequenceTracer::~SequenceTracer()
{
    Stack[Level] = 0; // Reset the sequence number
    Level--; // Decrease the level
    if (Level < 0) // If we are finished
    {
        delete OutStream; // Write to the file and delete stream
        OutStream = 0; // Reset the stream pointer
    }
}
//////////////////////////////////////////////////////////////////////

使用该类

使用此类非常简单,只需三个步骤

  1. 在要跟踪函数序列的 CPP 文件中包含 SequencTracer.h
  2. 在应用程序的早期阶段(例如,应用程序构造函数)调用静态函数 Start 并将要创建的文件名提供给此函数,该文件将存储所有序列
  3. 在你想了解其用法的任何函数的开头,在堆栈中实例化一个该类的对象

在运行应用程序并且级别小于 0 之后,您可以查看序列文件的内容。它看起来像

Sample image

我专门制作了一个应用程序来测试这个类。我制作了两个辅助宏,以进一步简化该类的使用

#ifdef _DEBUG
#define SEQ_TRACE(txt) SequenceTracer unique_variable_name##__LINE__ (txt)
#define SEQ_START(fileName) SequenceTracer::Start(fileName)
#else
#define  SEQ_TRACE(txt)
#define SEQ_START(fileName)
#endif
// Thanks to Michael Dunn for ##__LINE__

历史

  • 2003 年 8 月 16 日:文章已提交,小幅更新。
© . All rights reserved.