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);
    OutputDebugString(buffer);

    // retrieve the variable arguments
    va_start(args, msg);
    vsprintf_s(buffer, msg, args);
    OutputDebugString(buffer);
    va_end(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 http://www.bfilipek.com and on Twitter @fenbf.

comments powered by Disqus

Featured

  • Compare New GitHub Copilot Free Plan for Visual Studio/VS Code to Paid Plans

    The free plan restricts the number of completions, chat requests and access to AI models, being suitable for occasional users and small projects.

  • Diving Deep into .NET MAUI

    Ever since someone figured out that fiddling bits results in source code, developers have sought one codebase for all types of apps on all platforms, with Microsoft's latest attempt to further that effort being .NET MAUI.

  • Copilot AI Boosts Abound in New VS Code v1.96

    Microsoft improved on its new "Copilot Edit" functionality in the latest release of Visual Studio Code, v1.96, its open-source based code editor that has become the most popular in the world according to many surveys.

  • AdaBoost Regression Using C#

    Dr. James McCaffrey from Microsoft Research presents a complete end-to-end demonstration of the AdaBoost.R2 algorithm for regression problems (where the goal is to predict a single numeric value). The implementation follows the original source research paper closely, so you can use it as a guide for customization for specific scenarios.

  • Versioning and Documenting ASP.NET Core Services

    Building an API with ASP.NET Core is only half the job. If your API is going to live more than one release cycle, you're going to need to version it. If you have other people building clients for it, you're going to need to document it.

Subscribe on YouTube