25

I have been debugging a particularly insidious bug which I now believe to be caused by unexpected changes which stem from different behavior when different headers are included (or not).

This is not exactly the structure of my code but let's just take a look at this scenario:

#include "Newly_created_header_which_accidentally_undefines_SOME_DEFINE.h"

// ...

#ifdef SOME_DEFINE
    code_which_i_believe_i_am_always_running();
#else 
    code_which_fails_which_i_have_forgotten_about(); // runtime error stack traces back here, but I don't know this... or maybe it's some strange linker error
#endif

I search through my git commits and narrow down the cause of the bug, compiling and running my code countless times, only to find after several hours that the only difference required for causing the bug is the inclusion of what appears to be a completely benign and unrelated header.

Perhaps this is a great argument for why the preprocessor basically just sucks.

But I like it. The preprocessor is cool because it lets us make shortcuts. It's only that some of these shortcuts, when not used carefully, bite us in the butt pretty hard.

So at this juncture it would have helped if I could use a directive like #echo "Running old crashy code" where I'll be able to see this during compilation so I could be tipped off immediately to start investigating why SOME_DEFINE was not defined.

As far as I know the straightforward way of determining if SOME_DEFINE is defined is to do something like

#ifndef SOME_DEFINE
    printf("SOME_DEFINE not defined!!\n");

This will surely get the job done but there is no good reason for this task to be performed at runtime because it is entirely determined at compile-time. This is simply something I'd like to see at compile-time.

That being said, in this situation, using the print (or log or even throwing an exception) may be an acceptable thing to do because I won't really care about slowing down or cluttering up the questionable code. But that doesn't apply if I have for instance two code paths both of which are important, and I just want to know at compile-time which one is being activated. I'd have to worry about running the code that does the preprocessor-conditioned print at the beginning of the program.

This is really just a long-winded way of asking the question, "Can I echo a string to the output during compilation by using a preprocessor directive?"

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Steven Lu
  • 41,389
  • 58
  • 210
  • 364
  • 4
    Use the `#error` directive? Or `#warning`, if the preprocessor supports it. – Daniel Fischer Jun 26 '12 at 22:59
  • 1
    `#warning` is more like it since it won't halt processing. But yes that's pretty much it. Please make an answer! – Steven Lu Jun 26 '12 at 23:00
  • I think there is also `#warn` \ `#warning` on some compilers, but I believe its non-standard and less universal. I've also seen `#pragma message("WARN")` and `#print` available on some. – jedwards Jun 26 '12 at 23:01
  • 1
    also, in c++ static_assert can be used. – A. K. Jul 01 '12 at 03:34
  • `static_assert` is suitable for this role and may be a bit more capable at certain things because it is after the preprocessor stage. Thanks! – Steven Lu Jul 01 '12 at 03:41
  • Possible duplicate of [Is there a portable way to print a message from the C preprocessor?](http://stackoverflow.com/questions/3826832/is-there-a-portable-way-to-print-a-message-from-the-c-preprocessor) – Brian Tompsett - 汤莱恩 Feb 14 '16 at 11:02

2 Answers2

27

If you use the #error directive, the output will be printed directly and the compilation will stop:

$ make days_in_month
cc     days_in_month.c   -o days_in_month
days_in_month.c:2:2: error: #error "ugly!"
make: *** [days_in_month] Error 1
$ 

This might not be quite what you wanted, but it gets the job done quickly.

$ cat days_in_month.c
#include <stdio.h>
#error "ugly!"
...

If you wish processing to continue, you can use #warning:

$ make days_in_month
cc     days_in_month.c   -o days_in_month
days_in_month.c:2:2: warning: #warning "ugly!" [-Wcpp]
$ head days_in_month.c 
#include <stdio.h>
#warning "ugly!"
sarnold
  • 102,305
  • 22
  • 181
  • 238
  • This will produce output that is easy to see. I was actually hoping for an option where I can define the exact string it spits out (so it can be as conspicuous as I want) but this will get the job done. – Steven Lu Jun 26 '12 at 23:04
  • Note that you're allowed to put whatever you want in the string; If you wanted a full screen of `XXX WARNING XXX` blocks, knock yourself out. :) (I wonder if terminal color escapes get through too?) – sarnold Jun 26 '12 at 23:06
  • @Linuxios: that was my _first_ attempt... :) My first version of this answer was just `#error`, until I thought to try something more verbose -- I was confident I had seen a way to introduce just a warning. – sarnold Jun 26 '12 at 23:07
  • Yup, but I won't be able to keep it short and sweet in a single line, it ends up being *at least* adding one warning to the output (which could be undesirable depending on how OCD I am) – Steven Lu Jun 26 '12 at 23:15
  • For example the editor I use now makes a popup output panel if there are any errors or warnings in the libclang analysis of the particular source file I'm editing. If my code has such a `#warning` directive it will cause this panel to stay visible even if my code is otherwise warning-free. That's... slightly frustrating because it eliminates the incentive for cleaning up my code to gain back those extra few hundred pixels of screen space. – Steven Lu Jun 26 '12 at 23:22
  • You can protect that `#warning` with `#ifdef` or `#ifndef` or whatever you wish, as you initially were trying for -- `#warning` works with the rest of CPP well enough. – sarnold Jun 26 '12 at 23:28
4

Answer more in line with what I was looking for is here: https://stackoverflow.com/a/3826876/340947

Sorry @sarnold

Community
  • 1
  • 1
Steven Lu
  • 41,389
  • 58
  • 210
  • 364