Problem with #elif

I'm using some #defines in my program, and having not used them a lot in the past, I'm not really familiar with all their quirks, but I'm getting a weird error and I think I'm using them correctly here, so I don't know what might be going on.

Here's the code:

#define STYLE 2

// STYLE 0 = normal, 1 = swapped idle and standby (PAT), 2 = solid when in standby, standby animation otherwise
// STYLE 2 also disables the overheat and overload functions, as well as venting, and heating up, and replaces the shotgun with the normal strobe animation but with alternative sound effects.

#if STYLE == 0
  const byte BARGRAPH_STANDBY = 1; // Safety on
  const byte BARGRAPH_IDLE = 2; // Ready to fire
  const byte BARGRAPH_FIRE = 3; // Black button
  const byte BARGRAPH_ALTFIRE = 4; // Red button
#elif STYLE == 1
  const byte BARGRAPH_STANDBY = 2; // Safety on
  const byte BARGRAPH_IDLE = 1; // Ready to fire
  const byte BARGRAPH_FIRE = 3; // Black button
  const byte BARGRAPH_ALTFIRE = 4; // Red button
#elif STYLE == 2
  const byte BARGRAPH_STANDBY = 9; // Safety on
  const byte BARGRAPH_IDLE = 1; // Ready to fire
  const byte BARGRAPH_FIRE = 1; // Black button
  const byte BARGRAPH_ALTFIRE = 1; // Red button
#endif

Seems fairly straightforward, and it compiles fine if STYLE = 0, but as soon as I set STYLE to anything else, I get errors that other functions in my code are undefined. My project has multiple tabs and I suspect what is happening here has something to do with how the Arduino IDE combines source files, but other than that I have no idea what might be wrong. I suppose my next step will be to replace those with #else and #if statements to see if that corrects the problem, but I'd still like to know what's up with the #elif.

I tried changing the name of the define, and the format of the #if block and I still have the same problem:

#define PACK_STYLE 1

// STYLE 0 = normal, 1 = swapped idle and standby (PAT), 2 = solid when in standby, standby animation otherwise
// STYLE 2 also disables the overheat and overload functions, as well as venting, and heating up, and replaces the shotgun with the normal strobe animation but with alternative sound effects.

#if PACK_STYLE == 0
  const byte BARGRAPH_STANDBY = 1; // Safety on
  const byte BARGRAPH_IDLE = 2; // Ready to fire
  const byte BARGRAPH_FIRE = 3; // Black button
  const byte BARGRAPH_ALTFIRE = 4; // Red button
#else
  #if PACK_STYLE == 1
    const byte BARGRAPH_STANDBY = 2; // Safety on
    const byte BARGRAPH_IDLE = 1; // Ready to fire
    const byte BARGRAPH_FIRE = 3; // Black button
    const byte BARGRAPH_ALTFIRE = 4; // Red button
  #else
    #if PACK_STYLE == 2
  const byte BARGRAPH_STANDBY = 9; // Safety on
  const byte BARGRAPH_IDLE = 1; // Ready to fire
  const byte BARGRAPH_FIRE = 1; // Black button
  const byte BARGRAPH_ALTFIRE = 1; // Red button
    #endif
  #endif
#endif

Specifically, what error message? Also, it would be useful to post your entire program.

The error is:
"mapToPort() was not declared in this scope"

That being a function in one of my tabs in the IDE.

The bulk of the code is much too large to post. And since I changed he name of the #define to something that can't possibly exist elsewhere the bug has to either be in that block of code there or it is related to how the IDE automatically includes functions when you use multiple tabs. I'm thinking it's the latter.

What happens when you place the directive:

#include <arduino.h>

at the top of your source file?

econjack:
What happens when you place the directive:

#include <arduino.h>

at the top of your source file?

No change.

More strangeness:

WORKS:

#define PACK_STYLE 0

#if PACK_STYLE == 0
  const byte BARGRAPH_STANDBY = 1; // Safety on
  const byte BARGRAPH_IDLE = 2; // Ready to fire
  const byte BARGRAPH_FIRE = 3; // Black button
  const byte BARGRAPH_ALTFIRE = 4; // Red button
#endif

WORKS:

#define PACK_STYLE 1

#if PACK_STYLE == 1
  const byte BARGRAPH_STANDBY = 2; // Safety on
  const byte BARGRAPH_IDLE = 1; // Ready to fire
  const byte BARGRAPH_FIRE = 3; // Black button
  const byte BARGRAPH_ALTFIRE = 4; // Red button
#endif

DOESN'T WORK:

#define PACK_STYLE 1

#if PACK_STYLE == 0
  const byte BARGRAPH_STANDBY = 1; // Safety on
  const byte BARGRAPH_IDLE = 2; // Ready to fire
  const byte BARGRAPH_FIRE = 3; // Black button
  const byte BARGRAPH_ALTFIRE = 4; // Red button
#endif

#if PACK_STYLE == 1
  const byte BARGRAPH_STANDBY = 2; // Safety on
  const byte BARGRAPH_IDLE = 1; // Ready to fire
  const byte BARGRAPH_FIRE = 3; // Black button
  const byte BARGRAPH_ALTFIRE = 4; // Red button
#endif

I think the problem is that the Arduino's quaint attempt to insert function prototypes for you is inserting them just before the first definition in your file, which places them inside the first #if section.

I'm really looking forward to the day that the Arduino developers provide an option to turn that 'feature' off. I'm sure it was added with the best of intentions but it was a bad idea even if done well, and it wasn't done well.

I think you should be able to avoid the problem by putting a variable definition above the first #if to encourage Arduino to put its code inserts there. Alternatively, add your own function declarations above your first function.

As a simple test, I took the Blink program and stuffed your preprocessor directives in it. I was getting messages that things like OUTPUT, pinmode, Serial, etc. were not in scope when STYLE was non-zero. When I put the #include in, the errors disappeared. This suggests that, for some reason, the declarations that are normally known to the environment were getting lost. I don't know enough about the Gnu preprocessor to know how it works, but if the mapToPort() function is unknown, build your own new header file and fill it with the function declarations from your other source files, as in:

public int mapToPort(int myPort); // Whatever the correct type specifier and arguments are...

and #include the new header file in each source file, and let us know what happens.

Your code added to Blink got translated to:

/*
  Blink
  Turns on an LED on for one second, then off for one second, repeatedly.
 
  This example code is in the public domain.
 */
 
 #define STYLE 2

// STYLE 0 = normal, 1 = swapped idle and standby (PAT), 2 = solid when in standby, standby animation otherwise
// STYLE 2 also disables the overheat and overload functions, as well as venting, and heating up, and replaces the shotgun with the normal strobe animation but with alternative sound effects.

#if STYLE == 0
  #include "Arduino.h"
void setup();
void loop();
const unsigned char BARGRAPH_STANDBY = 1; // Safety on
  const unsigned char  BARGRAPH_IDLE = 2; // Ready to fire
  const unsigned char  BARGRAPH_FIRE = 3; // Black button
  const unsigned char  BARGRAPH_ALTFIRE = 4; // Red button
#elif STYLE == 1
  const unsigned char  BARGRAPH_STANDBY = 2; // Safety on
  const unsigned char  BARGRAPH_IDLE = 1; // Ready to fire
  const unsigned char  BARGRAPH_FIRE = 3; // Black button
  const unsigned char  BARGRAPH_ALTFIRE = 4; // Red button
#elif STYLE == 2
  const unsigned char  BARGRAPH_STANDBY = 9; // Safety on
  const unsigned char  BARGRAPH_IDLE = 1; // Ready to fire
  const unsigned char  BARGRAPH_FIRE = 1; // Black button
  const unsigned char  BARGRAPH_ALTFIRE = 1; // Red button
#endif
 
// Pin 13 has an LED connected on most Arduino boards.
// give it a name:
int led = 13;

// the setup routine runs once when you press reset:
void setup() {                
  // initialize the digital pin as an output.
  pinMode(led, OUTPUT);     
}

// the loop routine runs over and over again forever:
void loop() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

To work around the problem, add "int dummy;" or other declaration before your #define.

PeterH, johnwasser:

Wow...I had no idea things worked this way...

Thanks for the help guys, I'm glad my instincts were correct and I wasn't screwing up something really basic. :slight_smile: