Search code examples
c++enumsarduino

Arduino/C++ Enum declaration position dependent


I am working on my first arduino project, where I came across the following behavior I would like to understand. The following code compiles with no issues:

enum TestEnum {TestValue1};
void test(){}
void setup(){}
void loop(){}
void foo(TestEnum &testArg) {}

But switching the first two lines

void test(){}
enum TestEnum {TestValue1};
void setup(){}
void loop(){}
void foo(TestEnum &testArg) {}

results in the following errors when compiling:

D:\Path\to\Arduino-Sketches\foo\foo.ino:5:10: error: variable or field 'foo' declared void
 void foo(TestEnum &testArg) {}
          ^~~~~~~~
D:\Path\to\Arduino-Sketches\foo\foo.ino:5:10: error: 'TestEnum' was not declared in this scope
D:\Path\to\Arduino-Sketches\foo\foo.ino:5:10: error: note: suggested alternative: 'isalnum'
D:\Path\to\Arduino-Sketches\foo\foo.ino:5:20: error: 'testArg' was not declared in this scope
D:\Path\to\Arduino-Sketches\foo\foo.ino:5:20: error: note: suggested alternative: 'test'
 void foo(TestEnum &testArg) {}
                    ^~~~~~~
                    test

Can anyone explain why an enum needs to be defined before all functions? Is this an Arduino IDE thing? If it is a general C++ thing, what is the rational for this?


Solution

  • It's caused by Arduino preprocessing from .ino to .cpp file. It's for "convenience" reasons so begginers doesn't have to add prototypes (you can only use functions after they are declared or defined) and of course #include <Arduino.h>. So:

    void test(){}
    enum TestEnum {TestValue1};
    void setup(){}
    void loop(){}
    void foo(TestEnum &testArg) {}
    

    Will be preprocessed as:

    #include <Arduino.h>
    #line 1 "C:\\Users\\mikusm\\AppData\\Local\\Temp\\arduino_modified_sketch_446733\\sketch_feb19a.ino"
    #line 1 "C:\\Users\\mikusm\\AppData\\Local\\Temp\\arduino_modified_sketch_446733\\sketch_feb19a.ino"
    void test();
    #line 3 "C:\\Users\\mikusm\\AppData\\Local\\Temp\\arduino_modified_sketch_446733\\sketch_feb19a.ino"
    void setup();
    #line 4 "C:\\Users\\mikusm\\AppData\\Local\\Temp\\arduino_modified_sketch_446733\\sketch_feb19a.ino"
    void loop();
    #line 5 "C:\\Users\\mikusm\\AppData\\Local\\Temp\\arduino_modified_sketch_446733\\sketch_feb19a.ino"
    void foo(TestEnum &testArg);
    #line 1 "C:\\Users\\mikusm\\AppData\\Local\\Temp\\arduino_modified_sketch_446733\\sketch_feb19a.ino"
    void test(){}
    enum TestEnum {TestValue1};
    void setup(){}
    void loop(){}
    void foo(TestEnum &testArg) {}
    

    And as you can see all the function prototypes (declarations) apeared before any function definition (eg before test() {})

    When you moved the function definition after the enum definition, it results into this:

    #include <Arduino.h>
    #line 1 "C:\\Users\\mikusm\\AppData\\Local\\Temp\\arduino_modified_sketch_473375\\sketch_feb19a.ino"
    enum TestEnum {TestValue1};
    #line 2 "C:\\Users\\mikusm\\AppData\\Local\\Temp\\arduino_modified_sketch_473375\\sketch_feb19a.ino"
    void test();
    #line 3 "C:\\Users\\mikusm\\AppData\\Local\\Temp\\arduino_modified_sketch_473375\\sketch_feb19a.ino"
    void setup();
    #line 4 "C:\\Users\\mikusm\\AppData\\Local\\Temp\\arduino_modified_sketch_473375\\sketch_feb19a.ino"
    void loop();
    #line 5 "C:\\Users\\mikusm\\AppData\\Local\\Temp\\arduino_modified_sketch_473375\\sketch_feb19a.ino"
    void foo(TestEnum &testArg);
    #line 2 "C:\\Users\\mikusm\\AppData\\Local\\Temp\\arduino_modified_sketch_473375\\sketch_feb19a.ino"
    void test(){}
    void setup(){}
    void loop(){}
    void foo(TestEnum &testArg) {}
    

    Notice where the enum TestEnum {TestValue1}; ended in real .cpp file

    Possible workarounds:

    • namespaces
    • multiple files: sketch.ino + sketch.cpp where ino contains only library includes (for auto detection) and sketch.cpp contains everything (all includes including Arduino.h and all libraries, loop, setup). EDIT: seems ino file can be empty and the libraries are detected from other source files