How to debug macros efficiently in VS?

2020-05-20 08:23发布

问题:

I've got a pretty complicated macro inside my (unmanaged) C++ code. Is there any way to expand macros in VS debugger? Or maybe there is another way to debug macros there?

F.e. I'd like to place a breakpoint inside it.

(Yes, I know macros are bad.)

回答1:

Go to either project or source file properties by right-clicking and going to "Properties". Under Configuration Properties->C/C++->Preprocessor, set "Generate Preprocessed File" to either with or without line numbers, whichever you prefer. This will show what your macro expands to in context. If you need to debug it on live compiled code, just cut and paste that, and put it in place of your macro while debugging.



回答2:

The compiler expands macros nicely. Get a compilation listing with the macros expanded.

Insert the expanded macro into your code. Recompile and you should be able to step through it, to do a simple test.

Generally when I am building a complicated macro, I hard code it first, and test it. Then I turn it into a macro.

For 2008, this may be of help



回答3:

I learned from http://www.codeproject.com/Tips/320721/Macro-expansion-in-VCplusplus the best way to debug macros.

And what i do is to create a cxx file named "test.cxx" and inside i only put the macro and a some uses example of a test.cxx:

#define GetMacro(param1) \
  public: void Get##param1(){ return m_##param1; }

GetMacro(MyVariable);

and in a command line i enter:

c:\ cl /EP test.cxx > output.cxx

When i open the output.cxx file there should be some blank lines and at the bottom the expanded macro, like:

public: void GetMyVariable(){ return m_MyVariable; };

You can test macros without compiling and that makes it quick.



回答4:

I heard all possible negative answers on the topic:

  • macros can only be expanded not evaluated
  • preprocessor should parse also include files
  • nested macros can be over-complicated
  • conditional preprocessing can be tricky
  • macros are evil just avoid them
  • etc etc....

They are all true, but IMO they collide with the reality of everydays programming.

In fact, working on old C project, where macros were mostly simply used as functions, this became of crucial importance for me. Generating all preprocessed files with /P works, but is overkilling and time consuming. I just needed a tool that expands a simple macro defined a few lines above or at maximum in other file.

How to do that?

  1. On Linux simply use GDB and his expand macros capabilities
  2. On windows I use https://www.jetbrains.com/resharper-cpp/ integrated into Visual Studio

So, Yes, in a practical sense, it is possible.



回答5:

If you want to see the expanded code generated by the preprocessor then you can get it using the -E flag using gcc. The command would be like this:

$ gcc -E <source code> -o <preprocessed file name>

You can replace the original source code using macro with the expanded code and place whatever break point that you want to place there.



回答6:

If you're using Visual Studio to work on C or C++ projects that use macros, get Resharper for C++ (I believe that there is a trial version). It allows you to click on a macro and expand it completely, or in stages. We have some extremely complicated, nested macros and it's the only way to understand them.



回答7:

Have I said that the macros are very complicated? I'd like to expand one or two layers only, not all macros (otherwise it is plainly unreadable)... while debugging

If there are not way too many macros you don't want to expand, then you can simply #undef them before the snippet you want to debug. Then compile with the [Generate Preprocessed File] as mentioned above. The compilation will fail but you will get a usable snipped in the preprocessed output with the correct expansions. Copy-paste, remove the #undef-s and debug.

Sadly, your best friends for dealing with C-style macros are inline, template and a good optimizing compiler.



回答8:

Use inline functions (force inlining if you really mean it) and stick to it! This will be more efficient (get only inlined if it brings performance if you optimize for perf) and maintainable. You loose much by using macros: type checking & safety.

Macros do not exist for the compiler, they only do for the preprocessor. This one makes text replacements without looking for side effects. So macros are actually never called and you cannot debug into them. No matter how you code a macro, misuse is always possible. Like in this example:

#define SQUARE(a) ((a)*(a))

Note already the ( `)´ to protect against replacements like SQUARE(3+2). But they do not protect against:

int a = 1;
int b = SQUARE(++a);

One would expect it to be 4 but you end up with 6 which is not really square. As it expands to int b = (++a)*(++a); You wouldn't have this trouble with inlined functions.

Note that the implementation of an inlined function has to be visible for the compiler at the places where you use it. Also debugging will be weird to the novice user: as there are many instances of an inlined function, you'll get a huge list of methods if you want to move the execution point to another place for example.



回答9:

Yes, you can.

Locate the preprocessed file generated by the preprocessor in the Debug folder.

So if your macro is written in testing.c file, the preprocessed file would be called testing.i

There you can see how the macro have been expanded.

To debug it, just copy paste this code to yours :)