82

I have a selection of #defines in a header that are user editable and so I subsequently wish to check that the defines exist in case a user deletes them altogether, e.g.

#if defined MANUF && defined SERIAL && defined MODEL
    // All defined OK so do nothing
#else
    #error "User is stoopid!"
#endif

This works perfectly OK, I am wondering however if there is a better way to check if multiple defines are NOT in place... i.e. something like:

#ifn defined MANUF || defined SERIAL ||.... // note the n in #ifn

or maybe

#if !defined MANUF || !defined SERIAL ||....

to remove the need for the empty #if section.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Toby
  • 9,696
  • 16
  • 68
  • 132
  • 4
    FYI: `defined` is an operator that is invoked like a function (just like `sizeof`. So if you call it like a function, your example will work fine. Also - you can use most logical operators (`==`, `!=`, `!`, `||`, `&&`) in preprocessor statements as well. – Richard J. Ross III Jun 21 '13 at 14:21
  • 5
    It's a general principle of boolean algebra that you can replace `!(x && y)` with `(!x || !y)`. http://en.wikipedia.org/wiki/De_Morgan%27s_laws – Vicky Jun 21 '13 at 15:09

2 Answers2

144
#if !defined(MANUF) || !defined(SERIAL) || !defined(MODEL)
Sergey L.
  • 21,822
  • 5
  • 49
  • 75
  • 1
    Is it necessary to add the parens or can it be "#if !defined MANUF || ..."? – TimK Oct 10 '16 at 14:50
  • @TimK From what is written above, I'd say "yes". I could well be wrong; this is just an assumption. – wizzwizz4 Nov 28 '16 at 18:35
  • 5
    Actually you don't, but I'd recommend it for readability. https://godbolt.org/g/O48eun – T'n'E Mar 16 '17 at 10:20
  • Really? This seems easier to read to me, but it might just be personal preference: `#if !defined MANUF || !defined SERIAL || !defined MODEL` – kayleeFrye_onDeck Sep 15 '17 at 19:24
  • 10
    One benefit to the parens is that if `MANUF` happens to be a compound statement (ie. 1 + 1) then you'll be checking the whole statement, not just the first piece of it. – Tyler Dec 13 '17 at 14:06
8

FWIW, @SergeyL's answer is great, but here is a slight variant for testing. Note the change in logical or to logical and.

main.c has a main wrapper like this:

#if !defined(TEST_SPI) && !defined(TEST_SERIAL) && !defined(TEST_USB)
int main(int argc, char *argv[]) {
  // the true main() routine.
}

spi.c, serial.c and usb.c have main wrappers for their respective test code like this:

#ifdef TEST_USB
int main(int argc, char *argv[]) {
  // the  main() routine for testing the usb code.
}

config.h Which is included by all the c files has an entry like this:

// Uncomment below to test the serial
//#define TEST_SERIAL


// Uncomment below to test the spi code
//#define TEST_SPI

// Uncomment below to test the usb code
#define TEST_USB
netskink
  • 4,033
  • 2
  • 34
  • 46