Code Focused

Navigate Quickly from OutPut Window to Source Code

As you're debugging in Visual C++, sometimes you'll see a message in the Output Windows and then try to go the code it refers to, which can take a few steps. Here's a little trick in coding efficiency that simplifies moving from log messages to source code.

When you debugging C++ code, let me guess what steps you take: trace values using printf, TRACE, outputDebugString, etc., and scan the log in the output window, console or even a file. It's already an efficient approach, but in Visual Studio, there's a nice trick that allows you to move quickly from the debug output window to a particular line of code.

All you have to do is to use the following format:

"%s(%d): %s", file, line, message

When writing logs into VS output window/Debug, you'd write:

myfile.cpp(32) : Hello World

You can now double-click on the line in VS output window, and immediately VS opens myfile at line 32. Figure 1 shows an example.

Figure 1: Double-Clicking on the Output Takes You Directly to the Code

Why is it so important? In my case, I've lost a lot of time when I tried to look for the origin of some log output. When I see a message, I copy it, search the solution, and then usually after scrolling around I finally get to the right line of code. You cannot beat this double-clicking approach, which is much more efficient!

Now that you know the proper format of the message, how do you use it in the code? Let's go step by step.

First of all, you need to output the message using OutputDebugString:

OutputDebugString("myfile.cpp(32) : super");

Secondly, it's better to wrap the above function with a trace/log macro:

#define MY_TRACE(msg, ...) MyTrace(__LINE__, __FILE__, msg, __VA_ARGS__)

You can use it in the following way:

MY_TRACE("hello world %d", myVar);

The above code will call the MyTrace function that internally calls OutputDebugString.

So, why a macro? It's for convenience. Otherwise, we would have to pass line number and filename manually. File and Line cannot be fetched inside MyTrace because it would always point to source code where MyTrace is implemented -- not the code that logs something.

What is __FILE__ and __LINE__? Those are predefined macros that can be used in your code. As the name suggest they expand into the filename of the source code and the exact line. To control the __FILE__ macro you can use the compiler option /FC. The option makes filenames longer (full path), or shorter (relative to the solution dir). Please note that /FC is implied when using Edit and Continue.

And here's the implementation of MyTrace:

void MyTrace(int line, const char *fileName, const char *msg, ...)
    va_list args;
    char buffer[256] = { 0 };
    sprintf_s(buffer, "%s(%d) : ", fileName, line);

    // retrieve the variable arguments
    va_start(args, msg);
    vsprintf_s(buffer, msg, args);

The implementation is in ASCII; as homework, rewrite this into Unicode.

And finally, what do you do when you cannot output to Debug stream? I suggest a consistent format of the messages. For example, you can always start with the filename and a function name. Then, at least you reduce searching times. So, instead of this:

LOG("my input variable: %d", myVar);

it's definitely better to write this:

LOG("TestClass::DoStuff(): my input variable: %d", myVar);

or even better, with the additional file name and line number.

In this tip, we've covered a technique that makes easier to move from the message to its origin in the source code. It saved me a lot of time, and I hope it improves your workflow as well.

Next time we'll cover how to change code at runtime and how can it help with debugging/testing. So stay tuned.

About the Author

Bartlomiej Filipek is a software developer in Poland who specializes in C++, Windows and graphics programming. He worked for a number of companies developing multimedia, document editors, games, graphics drivers and flight planning systems, and has taught game development at local university. Follow Bart's blog at and on Twitter @fenbf.

comments powered by Disqus


Subscribe on YouTube