28

When debugging my code I quite often want to know the value of #define'd constants. But the debugger does not appear to know their values. This means I have to chase around looking at include paths etc to find the #define line. Is there some trick to make this easier?

UPDATE: I had to award the green tick to Tony D for his detailed answer of the headline question, but I have also upvoted the use of const instead of #define (I also tested that enum works too). Finally the use of F12 to find the original #define line was another good idea.

UPDATE 2023: Seven years after I originally asked this question, I noticed that Visual Studio 17.5.0 finally allows you to see the expansion of #define's

Mick
  • 8,284
  • 22
  • 81
  • 173
  • 2
    In the general case probably not because the resulting string of preprocesing a define is not necessarily an assignable value. – Peter - Reinstate Monica Sep 18 '15 at 10:30
  • 1
    Look for equivalent of `gcc -E` for your compiler. – Nawaz Sep 18 '15 at 10:31
  • I don't think it's possible. The defines are replaced before compilation, so no traces of them are left in the binary, thus the debugger can't possible know anything about them. – SingerOfTheFall Sep 18 '15 at 10:31
  • 9
    Some compilers do (optionally) include macro definitions in the final executable, specifically to aid debuggers. But if your compiler doesn't, that won't help you. –  Sep 18 '15 at 10:33
  • 1
    Because there is no such thing as "#define'd constants". All the lines that start with `#` are interpreted and removed by the pre-processor. A simple `#define`s like `#define PI 3.14159` tells the pre-processor to replace any occurrence of `PI` with `3.14159` and that's what it does. The `#define`s with arguments work in a similar way (their usage is replaced with expressions that use their arguments). The compiler and the rest of the compiling chain don't see them because they don't exist any more after the pre-processing (which is the first step of the compilation process). – axiac Sep 18 '15 at 10:35
  • 2
    Considering how complex #define macros can get, I'm amazed that there hasn't been more demand for features to help debug them. – Simba Sep 18 '15 at 13:01

7 Answers7

42

For whatever 10 minutes on Google's worth, it seems Visual Studio doesn't support this.

Some compilers do attempt this, but there's a reason it's a bit fragile / best-effort...

To first rehash and knock down the common but bogus explanation for this: there's a conceptually distinct preprocessing step that substitutes text for the uses of preprocessor macros before "proper" compilation begins, but there's really no reason the preprocessing stage can't pass a record of the #define and #undefine statements onwards for inclusion with other debug information.

What is a pain is that what is intuitively and commonly considered "#define-ing a preprocessor constant" isn't anything like...

const Some_Type some_identifier = some_value;

...in that the latter has a specific location in the application's namespace heirarchy and really can't be changed, while a #define can be #undef-ined and re-#defined any number of times, such that the "value" of a preprocessor macro at a particular line of code can depend on how that line's been included in the translation unit: each inclusion of the same line in each translation unit could have a different value (or no value) for that macro.

For this reason, displaying the "value" of a macro as you're debugging through some code is problematic - it's only guaranteed to have a single value at a particular line in a particular translation unit, but programmers normally want debuggers to show and navigate programs in terms of lines in source files.

Consider:

use_x.h

class T ## X {
    void g() { ... }
};

some_app.cc

#define X 2783
#include "use_x.h"
#undef X
#define X 2928
#include "use_x.h"
void f() {
    const int last_x = X;
}

If your debugger's stepping through f() above, X can be said to be 2928, but what if you're stepping through a version of g() - the debugger would have a tough time understanding there's some connection between the class name and the value of X used to create it, or working out what to display some other way....

It gets worse if you hover a mouse over a macro while stopped at some other line - possibly linked in from a different translation unit - it can be impossible for the debugger to know whether you're interested in the last value of that macro that your execution has passed through, or the next value it might have if execution continues (if it can even predict any branching that may happen first), or the value (if any) of the macro at the line the debugger's stopped at.

So, some tool chains (compilers / debug-info-encodings / debuggers) just don't buy into this mess. Better tools might track simple cases then display nothing - or a list of possible values - for cases too complex to analyse. Displaying wrong values is much worse than nothing.


It doesn't help within the debugger, but when macro values/substitutions need to be reviewed you can try cl /E (for GCC/clang the option's -E) to provide preprocessed output for a translation unit - you can then see what substitutions have been made by the preprocessor.

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • Just wanna emphasize the important point from paragraph 3: although the standard defines preprocessing and building as separate abstract translation phases, in no way does this necessarily have to impact the design of an actual compiler implementation. Compiler can do what it wants, including promoting variable-like macros to real variables where appropriate - if so designed. Most just aren't. – Alex Celeste Sep 18 '15 at 12:44
  • 1
    One thing I've long wanted would be a multi-column debugger (where columns which could be resized or enabled/disabled) which would in one column show the source-ish code that was being generated (but possibly rewritten by the optimizer), in one column show the corresponding preprocessed original source code (possibly reformatted to add line breaks at sequence points) and in one column show the original source code. – supercat Sep 18 '15 at 15:27
16

Macros are evaluated and resolved by the preprocessor, before compilation. It's not just that the compiled program doesn't know their values: the compiled program contains no trace of them at all. There's nothing for your debugger to inspect.

Consider macros to be a code generation tool, and everything will become clear.

Some compilers do have a flag you can set to retain the values of various preprocessor definitions and list them in a special area with your executable for debugging purposes. I don't know how to get that to happen in VS, though. I would instead use the relevant switch for only running the preprocessor, then inspect the result.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • @black good luck trying to apply this wisdom to anything not started from scratch. – Dmitry Grigoryev Sep 19 '15 at 15:38
  • Thanks to the moderators for totally pointlessly removing my reply to @black. Good job. What I said was along the lines of, black is wrong; that is _not_ the bottom line of my answer, and I do not believe it's true in general either. – Lightness Races in Orbit Sep 19 '15 at 15:40
  • My comment begins as a logical _consequence_ of this behavior but, again, it's just a comment _I_ made. It's a step _after_ this Q&A. Anyway, @LightnessRacesinOrbit, I'll remove it. – edmz Sep 19 '15 at 15:58
4

'#Define'd constants are unknown to the debugger as they are preprocessed before compilation and their appearances in the code are substituted with the value.

If you want a constant value why not use const? That way you can see the value in the debugger and also enforce the compiler to check for anywhere you mistakenly try to change the value in the code. #define has none of that safety.

Lloyd Crawley
  • 606
  • 3
  • 13
3

Regarding "Visual Studio", the #define X 3 is parsed during the pre-processing and all appearances of X are replaced with 3. Thus when you move your mouse over it, the debugger won't show its value, like in any other statement that has 'hardcoded' value.

int res = y + 3;

If you move the mouse over 3 it won't show you 3 in a floating window.

Alex Lop.
  • 6,810
  • 1
  • 26
  • 45
2

The why they are not known has been answered.. I actually feel your pain. That's why for every project I start I actually keep track of the include paths, and before compiling I grep the paths to get the define's in a textfile which list the defines. I keep that at hand when debugging. It's a trick I guess :)

addition : Maybe really helpful.. I hope :) I'm not using the Visual Studio anymore myself, so I'm not 100% sure if it is possible in 2015, but : - set preprocess to a file to yes in configuration properties -> C / C++ -> preprocessor. - visual studio used to generate an .i file, and I hope 2015 still does the same, the next time you compile your program, since this is the output of the preprocessor. - opening this .i file, you can at least see what the actual expanded value of your macro is, and also enter this value in the watch window, while you are debugging.

that would just cost you an extra compilation, but help you 2nd time around, saving you precious time, you can spend on other things than folder-diving :)

2

Select the macro you are interested in, on the line you want to know its value.

Press F12.

This will jump to its definitions (as best the compiler can work out: a given line of code could have multiple definitions for the same #define!).

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
1
#define one 1

This is just text replacement. Even compiler do not know what is behind this "1" in code.

Macros are evaluated by preprocessor before compilation/linking stage.

More about compilation steps: How does the compilation/linking process work?

Community
  • 1
  • 1
Morlacke
  • 61
  • 6