Help Understanding #if directive

I am using Arduino 1.0 and the EthernetDNS.h library isn't compatible with 1.0; I get errors when I try to compile. Now with Arduino 1.0, I don't even need EthernetDNS.h library, so I tried to exclude it from being compiled when using Arduino 1.0, but I still get compile errors. When I comment out EthernetDNS.h it compiles fine. I didn't think the IDE would compile the library if I exclude it with an #if statement like below.

#if ARDUINO < 100
#include <EthernetDNS.h>
#endif

--Scott

#if defined(ARDUINO) && ARDUINO >= 100
  // new
#else
  // old
#endif

So in your case:

#if !(defined(ARDUINO) && ARDUINO >= 100)
  #include <EthernetDNS.h>   
#endif

Nick,
I've seen this style of check for ARDUINO revision in various arduino sources
and even recommended in the arduino release notes.
Why should ARDUINO need to be checked for existence?
Don't undefined macros evaluate to zero?

I use this quite often with no issues in the glcd library.
i.e. I don't use defined() to check for existence before comparing.

I'm guessing that there is something else going on.

ScottG, Are you using the IDE or makefiles?

Starting with about IDE 0018 ARDUINO is defined via commandline option to the compiler
via a hardcoded value in the IDE JAVA code rather than a header file.
(BAD mistake IMHO)
Because of this, its value is undefined when not using the IDE unless the Makefile also passes
it in to the compiler as a commandline option ( -DARDUINO=XXX )

So if you are not using the IDE, ARDUINO will potentially not be defined, and if it
is not defined, then your check will always succeed and the header file will always
be included regardless of the actual "arduino" version.

An easy check is to simply put a

#error blah blah error

inside the #if that you think should/should-not be processed, if you get the error you know
the #if is evaluating as true.

--- bill

Bill,

Looks like you are right. I just followed the earlier examples. So try this:

#if ARDUINO < 100
  #include <EthernetDNS.h>     // old version
#endif

Now with Arduino 1.0, I don't even need EthernetDNS.h library, so I tried to exclude it from being compiled when using Arduino 1.0, but I still get compile errors.

So what I recommended is what you started with, heh.

What compile errors?

I'm using Arduino 1.0 on my Mac desktop, but I still have Arduino 0022 on my laptop. I'll probably upgrade the laptop to Arduino 1.0 soon. It's easy for me to comment the line out when using Arduino 1.0, but I really wanted to get a better understanding of how #if works. It was not doing what I expected.

--Scott

Basically the value of ARDUINO is given the numeric value of the release #. And the #if statement works like a C if statement. In this case you are including EthernetDNS.h only when the arduino version is < 100

kb3dow:
Basically the value of ARDUINO is given the numeric value of the release #. And the #if statement works like a C if statement. In this case you are including EthernetDNS.h only when the arduino version is < 100

That part I know. But ARDUINO = 100, so it should not be including EthernetDNS.h, which it may not be when it's all done. But it's not totally ignoring it when when I compile the sketch because EthernetDNS.h has errors when compiled in Arduino 1.0. I was hoping that since my #if statement is false, the compile process would totally ignore EthernetDNS.h, but it doesn't.

1 Like

Can you show the offending code? Do you have multiple tabs in your project?

Here is a basic example:

voidloop {
if(button, 1);            // If the button is being pressed
digitalWrite(LED, HIGH);} // then turn on the LED
else;                     // otherwise, if the button is not being pressed
{digitalWrite(LED, LOW);} // turn the LED off
}

Example of what?

No:

if(button, 1);            // If the button is being pressed

That is not a proper test, and you don't want the semicolon.


No:

else;                     // otherwise, if the button is not being pressed

Lose the semicolon.

I'm not using tabs.

EthernetDNS.h doesn't compile under Arduino 1.0. It doesn't really matter why. You can find the library here if you're interested:
http://code.google.com/p/arisgames/source/browse/trunk/arduino/libraries/EthernetDNS/?r=2002

I did a little experiment. I wrote the following sketch. The file ThisFileDoesNotExist.h does not exist. This code compiles without errors. This is what I would expect. The #if statement is false, so it just skips the include directive.

#define TEST1 100
#if TEST1 < 100
 #include <ThisFileDoesNotExist.h>
#endif
void setup(){}
void loop(){}
#define TEST1 100

But, the sketch below does give me errors. EthernetDNS.h does exist (but doesn't compile with Arduino 1.0). It appears that since this file really exists, the IDE is processing it, even though it's supposed to skip it.

#define TEST1 100
#if TEST1 < 100
 #include <EthernetDNS.h>
#endif
void setup(){}
void loop(){}

Yes, well I don't think the IDE honours the #if directive. So it sees the include and tries to compile the file. However I'm guessing the errors are in EthernetDNS.cpp, not your file. So you might edit that and put the entire contents inside the #if directive. So even though it is compiled, it won't do anything.

Here is some code that someone was gracious enough to help me with running an LED in an off, dimmed, and bright state depending on the digital inputs off both a slide switch and a push button. This code also includes debouncing information.

Please note: I didn't write it in the code, but you will see in the analogWrite lines that the LED is connected to pin 9.

Basic explanation of operation:
If the slide switch is turned on, the turn the LED on dimmed
If the button is pressed while the slide switch is turned on, turn the LED on full power
If the button is released while the slide switch is turned on, return the LED to the dimmed state
If the slide switch is turned off, turn the LED off
If the button is pressed while the slide switch is turned off, turn the LED on to full power
if the button is released while the slide switch is turned off, turn the LED off

Now, here's the code on a silver platter
(I like silver platters. Someone gave me a silver platter and now I clone it (copy and paste) and give one to you!):

// constants won't change. They're used here to 
// set pin numbers:
const int BUTTONpin = 12;         // the number of the pushbutton pin
const int SWITCHpin = 7;          // the number of the pushSWITCH pin

// Variables will change:
int BUTTONstate;                  // the current BUTTONreading from the input pin
int lastBUTTONstate = LOW;        // the previous BUTTONreading from the input pin
long lastBUTTONDebounceTime = 0;  // the last time the output pin was toggled

int SWITCHstate;                  // the current SWITCHreading from the input pin
int lastSWITCHstate = LOW;        // the previous SWITCHreading from the input pin
long lastSWITCHDebounceTime = 0;  // the last time the output pin was toggled

long debounceDelay = 100;          // the debounce time; increase if the output flickers

void setup() {
  pinMode(BUTTONpin, INPUT);
  pinMode(SWITCHpin, INPUT);
}

void loop()
{
  getSWITCHreading();
  getBUTTONreading();
  
  //SWITCHstate is the current state of the SWITCH
  //BUTTONstate is the current state of the BUTTON
  
  if(SWITCHstate==1)       //if SWITCH is on
  {                        //and
    if(BUTTONstate == 1)   //if BUTTON is pressed
    {                      //then
      analogWrite(9, 255); //LED Full Power
    }                      //but
    else                   //if BUTTON not pressed
    {                      //then
      analogWrite(9, 50);  //LED Dimmed
    }
  }
  else                     //or if switch is off
  {
    if(BUTTONstate == 1)   //if BUTTON is pressed
    {                      //then
      analogWrite(9, 255); //LED Full Power
    }                      //otherwise
    else                   //if BUTTON not pressed
    {                      //then 
      analogWrite(9, 0);   //LED Off
    }
  }
}

//This is all the debouncing stuff...

void getSWITCHreading()
{
  // read the state of the switch into a local variable:
  int SWITCHreading = digitalRead(SWITCHpin);
  
  // check to see if you just pressed the SWITCH 
  // (i.e. the input went from LOW to HIGH),  and you've waited 
  // long enough since the last press to ignore any noise:  

  // If the switch changed, due to noise or pressing:
  if (SWITCHreading != lastSWITCHstate) {
    // reset the debouncing timer
    lastSWITCHDebounceTime = millis();
  } 
  
  if ((millis() - lastSWITCHDebounceTime) > debounceDelay) {
    // whatever the SWITCHreading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    SWITCHstate = SWITCHreading;
  }
  
  // save the SWITCHreading.  Next time through the loop,
  // it'll be the lastSWITCHstate:
  lastSWITCHstate = SWITCHreading;
}

void getBUTTONreading()
{
  // read the state of the switch into a local variable:
  int BUTTONreading = digitalRead(BUTTONpin);
  

  // check to see if you just pressed the button 
  // (i.e. the input went from LOW to HIGH),  and you've waited 
  // long enough since the last press to ignore any noise:  

  // If the switch changed, due to noise or pressing:
  if (BUTTONreading != lastBUTTONstate) {
    // reset the debouncing timer
    lastBUTTONDebounceTime = millis();
  } 
  
  if ((millis() - lastBUTTONDebounceTime) > debounceDelay) {
    // whatever the BUTTONreading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    BUTTONstate = BUTTONreading;
  }

  // save the BUTTONreading.  Next time through the loop,
  // it'll be the lastBUTTONstate:
  lastBUTTONstate = BUTTONreading;
  
}

Notice the use of if and else in pairs.

If statement is true, then do this, otherwise (else) do this instead.
Hope this helps your understanding!

editor3000,

I don't think you understand what we are talking about. You're examples are for if statements that are executed by arduino while the program is running. The #if is something different, it's a pre-processor directive tells the IDE how to compile, not run, the program.

Check out: http://www.cplusplus.com/doc/tutorial/preprocessor/

Well, OK then.
My bad.
I thought I was teaching, but it was you who taught me.
That's why I'm still a noob!:stuck_out_tongue:

Yes, well I don't think the IDE honours the #if directive.

Yes, the IDE does preprocessor stuff. I used it in my FTP code.

Actually, I used #define and #ifdef, and if it preprocesses those ok, it should do an #if with no problem.