Stupid C preprocessor tricks

So, I have a #define like so:

#define GOOBER 1234

And later on in the code, I need this number as a string. I could do:

#define GOOBER 1234
#define GOOBER_STRING "1234"

And hope everyone remembers to update it when they change GOOBER. Or I could do:

char goober_str[100];
sprintf(goober_str, "%u", GOOBER);

But I die a little every time I type those lines. Surely, surely there is some kind of C preprocessor trick to do this all automagically for me?

I first thought of the the stringify operator, #:

#define GOOBER_STRING #GOOBER

But that would be the equivalent of:

#define GOOBER_STRING "GOOBER"

But it turns out that if you do two levels of evaluation, you can get the value – see the entry on stringification in the cpp docs.

The solution:

#include <stdio.h>                                                             

#define GOOBER 1234                                                             

#define xstr(s) str(s)                                                          
#define str(s) #s                                                               
#define GOOBER_STR xstr (GOOBER)                                                

int                                                                             
main(int argc, char *argv[])                                                    
{                                                                               
printf("goober %u\n", GOOBER);                                                
printf("goober_str %s\n", GOOBER_STR);                                        
return 0;                                                                     
}

$ ./goober 
goober 1234
goober_str 1234

(Thanks to for playing code teddy bear and bringing up stringification again.)

(Note: I removed all comments and disabled new ones – it was just an unfolding disaster. Sorry to those of you who left useful comments that are now lost in space.)

11 thoughts on “Stupid C preprocessor tricks”

  1. off topic / nit picking

    Might want to be careful using phrases including “Final Solution” (google for it)… or so something told me long ago.. so I’m just passing it on.

  2. Re: off topic / nit picking

    Yes, I have heard of the Nazis and the Holocaust, but thanks for the tip to google it – apparently not everyone is familiar with the phrase. Which is exactly why I went ahead and used it and just hoped that it had been sufficiently reclaimed/defused/whatever – clearly not.

    (What version of Godwin’s law deals with people who haven’t heard of the Nazis?)

  3. Re: off topic / nit picking

    Nonense. Dave Chinner applied it to threaded XFS filesystem validation and no Jews died as a result.

  4. Re: off topic / nit picking

    Let’s see… has it been long enough for the Holocaust to be funny yet? Testing, one two three… No! Okay, kids, don’t make me screen this thread.

  5. I remember hitting this some time ago. Drives me nuts. :-)

    Now if I can find a semi-automated way to stringify enums to make debug printouts more friendly.

    BTW, I forgot to mention: This stringification technique works really well in concert with ANSI C concatenation when generating “location identifiers” in debug strings using __LINE__. Quick example:


    #include <stdio.h>

    #define xstr(x) str(x)
    #define str(x) #x

    main()
    {
    puts("line " xstr(__LINE__));
    puts("line " xstr(__LINE__));
    puts("line " xstr(__LINE__));
    puts("line " xstr(__LINE__));

    return 0;
    }

    Output:


    line 8
    line 9
    line 10
    line 11

    I’ve used this for tracking where structures get allocated and frobbed so I can dump their “history” if I’m chasing a particularly bizarre bug. I wrap the real function calls in macros that capture __FILE__ and __LINE__ and do something interesting with it.

    Not a oft-used tool, but useful when it’s necessary.

  6. Re: off topic / nit picking

    Dave used a phrase that he hadn’t associated with any historical event and the only person that arguably came to harm as a result was himself. Using words that happen to be associated with unpleasent historical events doesn’t imply endorsement of that event, and I certainly wouldn’t want anyone to believe that either myself or Dave were in any way in favour of any form of racial segregation or extermination.

  7. Re: off topic / nit picking

    Continued because Sean threw a pillow at me and it landed on the keyboard and posted the article:

    It’s an awkward situation. I prefer being able to use language without having to worry about exteral contexts, but obviously the real world indicates that I can’t do that. I tend to constrain my usage of English to things that I suspect won’t be offensive, working within the limits of my own cultural context. Someone with a different cultural context is obviously going to have different constraints to me. Judging by the same standards isn’t sensible, and I don’t think the presence of a specific phrase inherently implies any specific racial distaste.

  8. This is also exactly what the Linux Kernel does. You can see this by running ‘make V=1’:

    gcc -Wp,-MD,scripts/mod/.empty.o.d -nostdinc -isystem /usr/lib/gcc/i386-redhat-linux/4.1.2/include -D__KERNEL__ -Iinclude -include include/linux/autoconf.h -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-declaration -Os -fno-stack-protector -m32 -msoft-float -mregparm=3 -freg-struct-return -mpreferred-stack-boundary=2 -march=i686 -mtune=pentium3 -mtune=generic -ffreestanding -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -pipe -Wno-sign-compare -fno-asynchronous-unwind-tables -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -Iinclude/asm-x86/mach-generic -Iinclude/asm-x86/mach-default -fomit-frame-pointer -Wdeclaration-after-statement -Wno-pointer-sign -D”KBUILD_STR(s)=#s” -D”KBUILD_BASENAME=KBUILD_STR(empty)” -D”KBUILD_MODNAME=KBUILD_STR(empty)” -c -o scripts/mod/empty.o scripts/mod/empty.c

    (In particular, notice the -D”KBUILD_STR(s)=#s” and -D”KBUILD_MODNAME=KBUILD_STR(empty)” parts.)

  9. Visions…

    of Al Stavely or Jefu classes dance through my heads..

    While I didn’t take too many CS courses, I roomed with several CS majors.. and this seemed to follow a meme of strange pragmas that one prof had people use and then they of course went far with it. I think it started with going through some old shell source code where the C compiler played a Prolog or similar compiler via preprocessor.

    I just can’t remember if it was Stavely or Jefu that had me diving through alt.net.c.madness to figure out what stupid things I could do to keep up with the Ollix’s.

Comments are closed.