72

It seems I often spend way too much time trying to get a #define macro to do exactly what i want. I'll post my current dilemma below and any help is appreciated. But really the bigger question is whether there is any utility someone could recommend, to quickly display what a macro is actually doing? It seems like even the slow trial and error process would go much faster if I could see what is wrong.

Currently, I'm dynamically loading a long list of functions from a DLL I made. The way I've set things up, the function pointers have the same nanes as the exported functions, and the typedef(s) used to prototype them have the same names, but with a prepended underscore. So I want to use a define to simplify assignments of a long long list of function pointers.

For example, In the code statement below, 'hexdump' is the name of a typedef'd function point, and is also the name of the function, while _hexdump is the name of the typedef. If GetProcAddress() fails, a failure counter in incremented.

if (!(hexdump = (_hexdump)GetProcAddress(h, "hexdump"))) --iFail;

So let's say I'd like to replace each line like the above with a macro, like this...

GETADDR_FOR(hexdump )

Well this is the best I've come up with so far. It doesn't work (my // comment is just to prevent text formatting in the message)...

// #define GETADDR_FOR(a) if (!(a = (#_#a)GetProcAddress(h, "/""#a"/""))) --iFail; 

And again, while I'd APPRECIATE an insight into what silly mistake I've made, it would make my day to have a utility that would show me the error of my ways, by simply plugging in my macro.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Randy
  • 751
  • 1
  • 6
  • 5

5 Answers5

119

enter image description hereGo to https://godbolt.org/. Enter your code in the left pane and select compiler as gcc put the argument as -E in the right pane. Your pre-processed code will appear on the right.

Mohit
  • 1,859
  • 1
  • 16
  • 25
  • 4
    Great tool! Should be the top answer as it requires the least amount of work. – David Mar 20 '18 at 17:28
  • 1
    For MSVC (Visual C++), set `/E` as a compiler option, then open up the Output panel (tab at the bottom). You can also then drag this Output panel anywhere in the page. –  Jun 08 '18 at 13:38
  • For another option, https://repl.it can be of use. Just start a new repl to choose language and paste the code on the left editor. Press F1 and type or find "shell" to open the shell, then type `gcc -E main.c` (assuming main.c is the file name) and the pre-processed code will be displayed. – Floella Aug 27 '20 at 18:53
  • 1
    Oh my Poseidon! I was thinking of using Godbolt's site, but didn't think I could get the preprocessed output. Obviously just put in the flags! Sometimes I feel like I was smarter when I was 14... – SO_fix_the_vote_sorting_bug Nov 24 '22 at 21:39
31

You can just run your code through the preprocessor, which will show you what it will be expanded into (or spit out errors as necessary):

$ cat a.c
#define GETADDR_FOR(a) if (!(a = (#_#a)GetProcAddress(h, "/""#a"/""))) 
GETADDR_FOR(hexdump)

$ gcc -E a.c
# 1 "a.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "a.c"
a.c:1:36: error: '#' is not followed by a macro parameter

GETADDR_FOR(hexdump)

In GCC, it's gcc -E foo.c to only preprocess the file.

Visual Studio uses the /P argument.

Mark Rushakoff
  • 249,864
  • 45
  • 407
  • 398
  • 1
    Thanks. I guuss I'll look into GCC. I suppos I was hoping for something that would just do an "expand as best it can" on my macro so i could see what it did visually. But I suppose just like errant C code, if my macro is total garbage, the pre-processor likely couldn't expand it at all. ;-). I guess I just need to read better documentation on the subject. But it still would be nice to have something that dumped the result of a sucessful expansion, because what is far worse than an error message, is an expansion that works, but doesn't generate the expected code! Will GCC /P do that? – Randy Jun 11 '10 at 13:30
  • 2
    @Randy: Actually, Boost Wave, which Jerry Coffin recommended, has a "replacement trace" feature where it outputs a file showing the steps it took during macro replacement. It's very verbose, because there are often a lot more steps than we usually think about, but it can be very useful, especially for complex or long macro definitions. – James McNellis Jun 11 '10 at 14:13
  • @Randy: I'm sort of the opinion that if your macro is complicated enough to need a sophisticated debugging tool that you're doing something wrong. :-) – Omnifarious Jun 11 '10 at 16:06
  • Omni, Then again, just about all our human efforts as programmers start out with a simple premise, but end up shooting all possible interpretations of Occam's razor to hell. ;-) – Randy Jun 11 '10 at 18:43
  • Is there any way to omit std includes from this? Getting a lot of unnecessary noise. – River Tam Sep 03 '18 at 19:00
6

http://visualstudiogallery.msdn.microsoft.com/59a2438f-ba4a-4945-a407-a1a295598088 - visual studio plugin to expand macroses

Kester
  • 69
  • 1
  • 1
4

You appear to be confused about what the exact syntax is for stringifying or token pasting in C preprocessor macros.

You might find this page about C preprocessor macros in general helpful.

In particular, I think this macro should read like this:

#define GETADDR_FOR(a) if (!(a = (_##a)GetProcAddress(h, #a))) --iFail

The trailing ; should be skipped because you will likely be typing this as GETADDR_FOR(hexdump);, and if you don't it will look very strange in your C code and confuse many syntax highlighters.

And as someone else mentioned gcc -E will run the preprocessor and skip the other compilation steps. This is useful for debugging preprocessor problems.

Omnifarious
  • 54,333
  • 19
  • 131
  • 194
  • Ah thank you! I certainly had a poor concept of proper use of the stringizer #. But it's usage and the concatination usage! Much appreciated! And thanks for the article link. That looks a lot more comprehensive than the breif notes I found in the MSDN! – Randy Jun 11 '10 at 13:27
2

You might want to take a look at Boost Wave. Like most of Boost, it's really more a library than a utility, but it does have a driver to act as a complete preprocessor.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • 1
    I don't know why this was downvoted... Wave does have a preprocessor implementation (though, it's not quite complete; there are several obscure aspects of macro replacement that it doesn't support). – James McNellis Jun 11 '10 at 01:36
  • @James: Yes, "complete" was probably the wrong word -- I just meant that it has driver code so you can compile and link it as a complete, executable program. If (for example) you want macro substitution *without* file inclusion, it's about the best starting point I know of though (and you *frequently* don't want file inclusion, as it can/will produce a lot of bulk to scan through to find what you care about). – Jerry Coffin Jun 11 '10 at 01:41
  • Maybe you could mention the [tracing ability](https://www.boost.org/doc/libs/1_75_0/libs/wave/doc/tracing_facility.html) of the wave driver application? Because I'm not aware of any other tool to show step by step how a macro is expanded. gdb might get a step by step expansion feature in the future (as mentioned here: https://stackoverflow.com/questions/57517469/how-to-perform-step-wise-expansion-of-a-c-preprocessor-macro)... – T S Feb 28 '21 at 22:00