enum - bizarre compiler behaviour?

I mostly program the Arduino by copying directly and/or copying aiming for syntactic and structural similarity. Anyone can see and modify Serial.println(“Hello World!”) and get his name printed, for example.

A large program I did not write compiled and ran just fine some few versions ago. Now I get an odd compiler error. I have distilled it into something truly puzzling, I hope. I have endeavoured to present the tiniest example.

The code compiles if one BUT NOT BOTH of the [enum and corresponding function taking the enum as an argument] is in the code. If both are in the code, the second fails with an error.

I downloaded 1.6.13 but did nothing else to the other files supporting the IDE, about which I have managed without learning anything. Could I have broken something, or overlooked something or was there a limit of one enum per program imposed some version ago? (I was on 1.6.12, same same)

In the real program, the declaration of the enum is in a header file tab, the header file is #included in the code tab where the function that uses it appears. As I say, it once worked.

Other solutions like using the old version of Arduino, copying the code from a working Ard (which I do have) seem like a bunch more trouble than coming to an understanding of what is happening here. I have googled fruitlessly and now throw myself upon your mercy and expertise.

Macintosh El Capitan 10.11.6 FWIW.

/*
 * Arduino 1.6.13
 * very odd ENUM error?
 */

/*

compiles only if one or the other of the two enum and functions are in the code - the second enum and fuction triggers

error: use of enum 'anotherENUM' without previous declaration
 void anotherFunction(enum anotherENUM xx)
                           ^
exit status 1
use of enum 'anotherENUM' without previous declaration

*/

/**/

enum anENUM {
  ABLE = 1, BAKER = 2, CHARLIE = 3,
};

void aFunction(enum anENUM xx)
{

}

/**/

enum anotherENUM {
  DELTA = 1, EPSILON = 2,
};

void anotherFunction(enum anotherENUM xx)
{

}

/**/

void setup() {

}

void loop() {

}

Works fine for me if I define the enums in a separate enums.h file:

enum anENUM {
  ABLE = 1, BAKER = 2, CHARLIE = 3,
};

enum anotherENUM {
  DELTA = 1, EPSILON = 2,
};

Otherwise, you probably run into the IDE's automatically-generated function prototypes ocuring before the enums they need...

The problem is that the IDE is generating function prototypes for you and it's placing them before the definition of the enum. I think that if you will write your own forward declaration of those functions in the code then the IDE won't try to generate them and everything will compile.

With this IDE the order that you do things in really matters. This compiles in 1.6.13 with no headers involved.

enum anENUM {
  ABLE = 1, BAKER = 2, CHARLIE = 3,
};

enum anotherENUM {
  DELTA = 1, EPSILON = 2,
};

void aFunction(enum anENUM);
void anotherFunction(enum anotherENUM);


void aFunction(enum anENUM xx)
{

}

/**/





void anotherFunction(enum anotherENUM xx)
{

}

/**/

void setup() {

}

void loop() {

}

Thank you for the rapid, kind and accurate responses. Now it remains to me to see if I hadn't carefully applied any or all of these advices already to the real code.

I did think I had cornered the problem having tried everything on the real code, we'll see. I've been around long enough to know that these days blaming the machine is the last thing one does. I've been at this long enough to know that one can overlook something obvious in the most carefully designed experiments.

On the other hand, Aruino seems to be in its own class. I've copied and used code that seems to get away with quite a bit of squirriliness. Not to malign squirrels.

Thanks again.

Okay, I am still missing something. Since your changes to my tiny example work, I looked carefully at the big program that was fine in earlier Arduino versions. These are pull quotes, so to speak, but are the essence of what I boiled down for the small example

in file/tab a7105.h I see

enum A7105_State {
    A7105_SLEEP     = 0x80,
    A7105_IDLE      = 0x90,
    A7105_STANDBY   = 0xA0,
    A7105_PLL       = 0xB0,
    A7105_RX        = 0xC0,
    A7105_TX        = 0xD0,
    A7105_RST_WRPTR = 0xE0,
    A7105_RST_RDPTR = 0xF0,
};

in file/tab a7105(.ino) I see

...

#include "a7105.h"

...

// Transmits the given strobe

void A7105_Strobe(enum A7105_State state)
{
    // NB: the CS pin must be lowered before and raised after every communication with the chip
    CS_LO();
    SPI.transfer(state);
    CS_HI();
}

...

I have tried some (seemingly) extreme measures including pulling the failing parts into separate tabs, it always trips up compiling the function A7105_Strobe.

Oddly, pulling out this set of code fragments into a teeny extension of my example sketch works fine, this is complete in two tabs ‘mysteryA7.ino’ and ‘enumheader.h’

/*
 * mysteryA7.ino
 * Arduino 1.6.13
 * very odd ENUM error?
 */


# include "enumheader.h"

void aFunction(enum anENUM xx)
{
 
}

void anotherFunction(enum anotherENUM xx)
{

}

// Transmits the given strobe

void A7105_Strobe(enum A7105_State state)
{ 
// NB: the CS pin must be lowered before and raised after every communication with the chip
    CS_LO();
    SPI.transfer(state);
    CS_HI();
}

void setup() {

}

void loop() {
}

and

// enumheader.h
#include <SPI.h>

enum anENUM {
  ABLE = 1, BAKER = 2, CHARLIE = 3,
};

enum anotherENUM {
  DELTA = 1, EPSILON = 2,
};


// strobe commands. These are used to set the transceiver mode
enum A7105_State {
    A7105_SLEEP     = 0x80,
    A7105_IDLE      = 0x90,
    A7105_STANDBY   = 0xA0,
    A7105_PLL       = 0xB0,
    A7105_RX        = 0xC0,
    A7105_TX        = 0xD0,
    A7105_RST_WRPTR = 0xE0,
    A7105_RST_RDPTR = 0xF0,
};

#define CS_PIN 10 
#define CS_HI() digitalWrite(CS_PIN, HIGH);
#define CS_LO() digitalWrite(CS_PIN, LOW);

I am ready to slap my forehead, I am just not seeing it.

The IDE puts automatically generated function prototypes after the first non-preprocessor line. Unfortunately that spot is ABOVE the declaration of the second ENUM. If you put in your own function prototype (after the declaration of the second ENUM) the Arduino IDE will not automatically generate one for that function. For example this sketch compiles fine on 1.6.12:

enum anENUM {ABLE = 1, BAKER = 2, CHARLIE = 3};

// The auto-generated function prototypes go here.

void aFunction(enum anENUM xx) {}

enum anotherENUM { DELTA = 1, EPSILON = 2};

// Function prototype
void anotherFunction(enum anotherENUM xx);

void anotherFunction(enum anotherENUM xx) { }

void setup() {}

void loop() {}

This is the C++ source file that the sketch gets turned into by the IDE if you comment out the function prototype:

#include <Arduino.h>
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000; background-color: #ffffff} p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #000000; background-color: #ffffff; min-height: 13.0px} span.s1 {font-variant-ligatures: no-common-ligatures}
#line 1 "/var/folders/cs/p6yz0z1m8xj9lf0059b_lzw00000gn/T/untitled562950451.tmp/sketch_dec09a/sketch_dec09a.ino"
#line 1 "/var/folders/cs/p6yz0z1m8xj9lf0059b_lzw00000gn/T/untitled562950451.tmp/sketch_dec09a/sketch_dec09a.ino"
enum anENUM {ABLE = 1, BAKER = 2, CHARLIE = 3};

#line 3 "/var/folders/cs/p6yz0z1m8xj9lf0059b_lzw00000gn/T/untitled562950451.tmp/sketch_dec09a/sketch_dec09a.ino"
void aFunction(enum anENUM xx);
#line 10 "/var/folders/cs/p6yz0z1m8xj9lf0059b_lzw00000gn/T/untitled562950451.tmp/sketch_dec09a/sketch_dec09a.ino"
void anotherFunction(enum anotherENUM xx);
#line 12 "/var/folders/cs/p6yz0z1m8xj9lf0059b_lzw00000gn/T/untitled562950451.tmp/sketch_dec09a/sketch_dec09a.ino"
void setup();
#line 14 "/var/folders/cs/p6yz0z1m8xj9lf0059b_lzw00000gn/T/untitled562950451.tmp/sketch_dec09a/sketch_dec09a.ino"
void loop();
#line 3 "/var/folders/cs/p6yz0z1m8xj9lf0059b_lzw00000gn/T/untitled562950451.tmp/sketch_dec09a/sketch_dec09a.ino"
void aFunction(enum anENUM xx) {}

enum anotherENUM { DELTA = 1, EPSILON = 2};

// Function prototype
//void anotherFunction(enum anotherENUM xx);

void anotherFunction(enum anotherENUM xx) { }

void setup() {}

void loop() {}

Note that it generates a function prototype for Line 10 between the two ENUM declarations. When the compiler sees that line it finds that it has not yet seen a declaration for the second ENUM and it reports an error in Line 10 (because the preprocessor directive has said “the next line is Line 10”).

YES! compiling now, albeit with warnings I am not sure weren't there before…

Thank you. I understood enough from your careful response to try a few things. A placement of my own prototype

void A7105_Strobe(enum A7105_State state);

directly before the full definition of that function jumps me over the hurdle. I'll try to get over my surprise!

In the meantime, so many work-arounds I contemplated resulted in a comedy of errors and dead ends that has truly rattled my confidence in my own state of knowledge and ability to work this IDE.

  1. google to find the (dumb) mistake. I did come across things that didn't take, because they seemed to make no sense - OK to have stuff in a header file, or even the downright necessity of doing, unlike anything in my 'code by faking it' working of languages and compilers (and text editors and OSes for that matter) with which I am, so to speak, less than intimate.

A. Move to an old version (but it doesn't change all the files that I never see, never care about, that go with the IDE app itself): Compiles but the (new?) avrdude doesn't like the programmer specs.

B. Look into getting the object code &c. off a working Arduino (or from a version of Arduino that can compile but not download) and downloading it to the new copy: possible, but looked like a long slog through a different swamp, as rewarding as it might have been.

C. Write around this use of 'enum'. After all, it is just syntactic sugar for defined constants and appropriate sized registers: an unbelievable and bewildering cascade of errors totally unrelated ensued.

D. look at release notes to see why and when this error would have started happening - as I have said, this is old code that has been deployed and functioning, insofar as one can tell, precisely the way I intended: lots of work, lots of changes and fixes, lots of stuff over my head or otherwise telling me not to spend lots of time. Lots of lots.

So thank goodness I had option E, asking for help

Not complaining, no! I should just take the time to internalize the somewhat different manner in which the Arduino IDE does its thing.

Again, thank you (all) for your kind and rapid attention.

The Arduino IDE is here to help non-programmers. :)

One thing that non-programmers run into is the fact that they have to declare a function before they use it. The IDE tries to hide that requirement by inserting prototypes. As you found out, inserting them above the declarations on which they depend doesn't work. They try to put them below the included libraries and that works most of the time. It doesn't work when there is an ENUM, STRUCT, TYPEDEF, or CLASS declared and used in the sketch. Non-programmers don't use those constructs so only experienced programmers get the resulting bizarre errors. :(