enum vs int, arduino screwing up

I have the following snippit declaration:

#define NUMBER_OF_MODES 4

enum EDIT_MODE {None, Low, High, Mode};

enum EDIT_MODE editMode = None;

Later in the code I do:

editMode = ++editMode % NUMBER_OF_MODES;

However the arduino compiler complains:

TempControl:96: error: no match for 'operator++' (operand type is 'EDIT_MODE')
editMode = ++editMode % NUMBER_OF_MODES;
^
exit status 1
no match for 'operator++' (operand type is 'EDIT_MODE')

Now, I know from years of C experience I know that an enum is an integer and you can do math operations on it. I've been doing it for years.

I changed the line to (editMode + 1) % NUMBER_OF_MODES;
and then it complained about the modulo operator,

I compile a test program on Linux gcc using the above code and it compiled and ran perfectly. No complaints about type mismatches.

So, it would seem to me that the arduino, or arm-gcc, has a problem.

tj

'editMode' can only be set to: None, Low, High or Mode

larryd:
'editMode' can only be set to: None, Low, High or Mode

Not true.

This works:

enum EDIT_MODE {None, Low, High, Mode};
enum EDIT_MODE editMode = None;

void setup() 
{
  Serial.begin(9600);
  Serial.println(editMode); //prints 0
  editMode=editMode+1;
  Serial.println(editMode); //prints 1
  editMode=5;
  Serial.println(editMode); //prints 5
}

void loop() 
{
  
}

Stronger type check compilation options - so it’s stupid to use ++ or modulo on a such a type editMode =(EDIT_MODE) ((((int) editMode) + 1) % NUMBER_OF_MODES); might work but is poor conceptually

tjp999:
I know that an enum is an integer and you can do math operations on it. I've been doing it for years.

Yeh, but it isn't any more in C++. You can explicitly cast to int and back again: (which will be frowned upon)

enum EDIT_MODE {None=0, Low, High, Mode};  // =0 to show some sort of intent

editMode= (EDIT_MODE)(((int)editMode +1) % NUMBER_OF_MODES);

Considering that you can define:
enum EDIT_MODE {None=42, Low=7, High, Mode};

I believe the argument was that iterating over an enum would require it to be some form of set and would need a data structure more than just a simple 'integer' to implement - but that would make it incompatible with 'old' enum. So they gave up and just enforced stronger typing and don't allow integer operations.

Trouble is the enum is still implemented like 'int', so you can do all sorts of nasty things as wilfredmedlin points out and force the enum to have a value which not been defined.

As J-M-L notes, you can add an integer, but the compiler will issue warnings unless you explicitly cast (as above)
EDIT example was:
editMode= (editMode+1) % NUMBER_OF_MODES; // issues warning

Yours,
TonyWilk

wilfredmedlin:
Not true.

This works:

enum EDIT_MODE {None, Low, High, Mode};

enum EDIT_MODE editMode = None;

void setup()
{
 Serial.begin(9600);
 Serial.println(editMode); //prints 0
 editMode=editMode+1;
 Serial.println(editMode); //prints 1
 editMode=5;
 Serial.println(editMode); //prints 5
}

void loop()
{
 
}

That’s good news, I have an application for this.

Thanks

Trouble is the enum is still implemented like 'int', so you can do all sorts of nasty things as wilfredmedlin points out and force the enum to have a value which not been defined.

this is actually by default, you can force a typeenum : uint8_t {AA,BB,CC} var=CC;

There is a difference between C and C++ :wink: The error message clearly refers to an issue with C++; you state that you use gcc on linux (and it compiles) which might imply that you use pure C on the linux system.

Too long ago that I coded on Linux and too lazy to fire up my linux system to test :wink:

TonyWilk:
so you can do all sorts of nasty things as wilfredmedlin points out and force the enum to have a value which not been defined.

I'm no expert though, and found that out by testing the use of enum'd states to use in switch...case. So I had the states eg 0-3 named in an enum just like OP, and then checked to see if eg 5 would be accepted as a case in the switch. Turns out it was, against my expectation hope that the enum would limit the states' range to 0-3.

So, and sorry if this goes off topic a wee bit, how can one (or, can one even) stipulate a range of allowed values. (I know, I should trap that as the switch...case's default: with a "no such state" massage.)

wilfredmedlin:
So, and sorry if this goes off topic a wee bit, how can one (or, can one even) stipulate a range of allowed values. (I know, I should trap that as the switch...case's default: with a "no such state" massage.)

The compiler will warn if you try to switch( someEnum ) with case elements which are not of that enum and will warn if all elements of the enum are not accounted for.

It is an argument (a good one in my book) that warnings should be treated as errors esp. for production code.

...but that still doesn't stop you casting away your sins :slight_smile:

Yours,
TonyWilk

TonyWilk:
The compiler will warn if you try to switch( someEnum ) with case elements which are not of that enum and will warn if all elements of the enum are not accounted for.

Hmmm, well I compiled this with verbose output, no warnings:

enum EDIT_MODE {None, Low, High, Mode};
enum EDIT_MODE editMode = None;

void setup()
{
  switch (editMode)
  {
    case None: break;
    case Low: break;
    case 5:
      break;
  }//switch
}

void loop()
{
}

Then made editMode=5 and it printed my message:

enum EDIT_MODE {None, Low, High, Mode};
enum EDIT_MODE editMode = None;

void setup()
{
  Serial.begin(9600);
  editMode = 5;
  switch (editMode)
  {
    case None: break;
    case Low: break;
    case 5:
      Serial.println("case is 5");
      break;
  }//switch
}

{
void loop()
}

But as you can see I'm switch-ing on editMode, should I use EDIT_MODE somehow rather?

If you want to change warnings to errors, you can edit platform.txt and add the -Werror=all compiler flag.

They do -Werror=all in the Arduino core for the ESP32 if you have File > Preferences > Compiler warnings set to "More" or "All". I like to see people taking warnings seriously but it does cause some confusion since people don't expect that preference setting to affect compilation.

wilfredmedlin:
Hmmm, well I compiled this with verbose output, no warnings:

You need to turn warnings on: File > Preferences > Compiler warnings > All > OK.

Verbose output is different. Actually I usually leave verbose output off since it makes for more scrolling to read warnings, which I always have turned on.

pert:
You need to turn warnings on: File > Preferences > Compiler warnings > All > OK.

Verbose output is different.

Crap, thanks for that @pert.

Now I see what @TonyWilk meant.

You got me worried there for a moment and had to test it... :o

For the record, you should see these warnings (edited):

sketch_feb08a.ino: In function 'void loop()':

warning: enumeration value 'High' not handled in switch [-Wswitch]
warning: enumeration value 'Mode' not handled in switch [-Wswitch]
warning: case value '5' not in enumerated type 'EDIT_MODE' [-Wswitch]

Yours,
TonyWilk

TonyWilk:
For the record, you should see these warnings (edited):

Yep, got exactly that.

Later in the code I do:

editMode = ++editMode % NUMBER_OF_MODES;

An assignment combined with a pre-increment. What could possibly go wrong.