Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

C++ Code Point Tracking

4.45/5 (5 votes)
20 Dec 2013CPOL2 min read 20K   135  
An ad hoc solution to mark and track code points in C++

Introduction

Although there shouldn't, there are times when it's uncertain which code points are run through during the execution of a program. There are many professional tools out there which range from static analysis to instrumented measures to get answers to such questions, but on some occasions, an ad hoc solution can be more effective.

Background

The approach to make this work is to make use of the pre program start initialization of static variables, but since all code points are in functions and therefore, the "static anker point" has to be put there somehow and so, the C++ feature of delayed initialization of static function variables has to be overcome.

This seems to be possible by adding an indirection through a template class (X) with a static member variable (progloc_) to enforce the initialization per template parameter which in turn is a wrapper struct which transports the needed information (_.FILE._ " at line " _.LINE._).

Putting this together, the most important code to achieve this could look like the following:

C++
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_); }

The S_._LINE_._ - trick which is used in the ProgLocation - ctor comes from here on SO.

C++
#define S(x) #x
#define S_(x) S(x)
#define S__LINE__ S_(__LINE__)

To track, the following is used:

C++
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

All it needs to track a code point is to put the macro:

C++
TRACE_CODE_POINT  

at the desired places and to call the report() method of the Test class at the end of the program.

Points of Interest

The provided solution is very dangerous for several reasons and should be used with care. Neither performance nor thread safety were considered. So far, the code has only been tested on MSVC 2010 and 2013.

If you're going to use the code, you might also consider adding some dispatching to the report method. The sample source provided in the zip at the start of the tip contains one such reporter and a console and a debug output window sink and also a handy helper to frame the main function.

History

  • 2013/12/20: First release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)