80

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.

2

5 Answers 5

134

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.

4
  • 4
    Great tool! Should be the top answer as it requires the least amount of work.
    – David
    Mar 20, 2018 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.
    – user1350534
    Jun 8, 2018 at 13:38
  • For another option, 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, 2020 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... Nov 24, 2022 at 21:39
34

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.

5
  • 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, 2010 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. Jun 11, 2010 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. :-) Jun 11, 2010 at 16:06
  • 1
    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, 2010 at 18:43
  • 1
    Is there any way to omit std includes from this? Getting a lot of unnecessary noise.
    – River Tam
    Sep 3, 2018 at 19:00
6

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

3
  • Where did the user mention Visual Studio? Oct 2, 2012 at 12:38
  • 2
    @AndrewBarber He mentions that he visited MSDN in a comment
    – xshoppyx
    Dec 5, 2012 at 11:34
  • 2
    The link is invalid Jun 20, 2023 at 5:29
5

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.

1
  • 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, 2010 at 13:27
3

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.

3
  • 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). Jun 11, 2010 at 1: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). Jun 11, 2010 at 1:41
  • Maybe you could mention the tracing ability 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: stackoverflow.com/questions/57517469/…)...
    – T S
    Feb 28, 2021 at 22:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.