IDE reorders code using structs, enums?

So I am aware to an extent that this is a problem which has come up before and there has not been much interest in fixing it, but it seemed like I should at least ask. Here's the test case which I did in platformio, though the arduino ide emits an equivalent error message.

void setup() {}
typedef struct {uint8_t x;} structType;
void myFunc(structType structInstance){}
void loop() {}
  
Compiling .pio\build\nanoatmega328\src\test.ino.cpp.o
C:/Users/User/Documents/PlatformIO/Projects/230808-001214-nanoatmega328/src/test.ino:2:13: error: variable or field 'myFunc' declared void
 typedef struct {uint8_t x;} structType;
             ^~~~~~~~~~
C:/Users/User/Documents/PlatformIO/Projects/230808-001214-nanoatmega328/src/test.ino:2:13: error: 'structType' was not declared in this scope
C:/Users/User/Documents/PlatformIO/Projects/230808-001214-nanoatmega328/src/test.ino:2:13: note: suggested alternative: 'struct'
 typedef struct {uint8_t x;} structType;
             ^~~~~~~~~~
             struct
*** [.pio\build\nanoatmega328\src\test.ino.cpp.o] Error 1

Through a LOT of investigation we are reasonably confident that what's happening here is that the IDE is reordering things in order to "help" which is resulting in the struct definition being moved after its first use. We are pretty sure this has also happened to us with enums before.

Yes I am aware that the custom is to put definitions at the top of the file or in a header, but the code above is valid in several different formal c standards and should compile.

At the very least the error message is extremely unhelpful because it refers to code the IDE has generated, as opposed to code I have written, and no matter what anyone thinks of the original code, that is not the right way to handle the situation.

This is a really big time sink and it would be great to think something could be done about it.

yes that's a known issue that did not get fixed. The IDE is generating prototypes for your functions and the type gets unknown

so better stick to the typical

typedef struct {uint8_t x;} structType;
void setup() {}
void myFunc(structType structInstance){}
void loop() {}

even if you are right, your code is legit.

Yeah the problem is that it causes really incredibly large and complicated problems for people with a codebase they have been working on for a while, and which for whatever reason then ends up creating this issue.

Please can have fix, this is tremendously awful.

add your complaints to Arduino's GitHub

(or better, find how to solve that and post a pull request)

Oh god no, git hub brings me out in a rash :confused:

1 Like

I don't think the staff would read your post here, sometimes they do (@pert for example)

Time to start using .h and .cpp files to organise big sketches :wink:

In case you're interested in what the IDE creates and passes to the compiler, you can check the verbose compiler output for the location where the temporary file is located (search for *.ino.cpp); on a Windows system, it will be somewhere in AppData\Local\Temp if not mistaken.

That is ultimately what we've done, but it was quite a large refactoring effort and we are not very sure what long term risks it creates.

We found the most straightforward way to do it was to move related chunks of code into .hpp files (tried .c and .cpp, which created problems of their own). There are some quite complicated issues with needing to #include certain things such as inttypes.h in order to have things as simple as uint8_t available.

My biggest concern is what unexpected issues this may cause in future because I will freely admit I don't really know what I'm doing and why it works the way it does. Really it's a workaround and my hope is that one day the arduino people will notice this problem and perhaps fix it.

the issues are at compile time as you saw. so the "risk" is more that it does not compile rather than do something weird at run time

I get that, but in the end if we are working on it and it won't compile, then it still creates a big complicated problem for us, and we still can't finish the job, even if it's at compile time rather than run time.

sure I understand it's a nuisance and would love a check box in the preferences to skip that prototype generation step...

Another option I've seen is to simply create a function prototype yourself:

void setup() {}
typedef struct {uint8_t x;} structType;
void myFunc(structType structInstance);
void myFunc(structType structInstance){}
void loop() {}

Yes I almost wrote a script to do that...

But I think when you consider it, having to basically just repeat the first line of a function is a pretty insane workaround. I don't think anyone could really claim that's a beautiful solution :slight_smile:

It's fairly common practice outside of Arduino to have a block of function prototypes when there's a bunch of functions and you don't want to worry about who calls whom and which function comes before which other functions (especially when you have mutual recursion):

void func1(int);
void func2(int);
void func3(int);

// ...

void func1(int x)
{
  func2(x);
}

void func2(int x)
{
  func3(x);
}

void func3(int x)
{
  func1(x);
}

Yes, I know, it's just that I think a lot of people use things like Arduino exactly because they want to get away from that kind of 1970s boiler plate!

1 Like

I don't find it horrifying that you have to tell the compiler a minimum amount of information (signature) about things you use before you use them... This feels natural to me.

1 Like

Maybe that applies to you. But most people begin with Arduino because it's a (relatively) easy way to achieve things with microcontrollers; they don't know about coding and they don't care as long as they can achieve what they want to achieve. And it's cheap as you don't have to pay for the IDE; when I started in the embedded world, compilers did cost a small fortune (I don't know how that is now as I only use the Arduino IDE and AVR based boards and don't have a need to look around for other IDEs).

If the people that start with Arduino were experienced programmers, they would basically straight away start splitting large code in .h and .cpp files to keep it manageable and organised. They would also (wisely) skip the multiple-ino approach (if they know that it exists) because it suffers from the same problem that you experienced.

drillinstructorjan

-Philosophically-
You are fighting several battles that you are not likely to win. You have an expectation of how things should work. Right or wrong, they DO NOT work the way you imagine/desire. You will be further ahead to accept that things in live work as they do and move on.

Personally I hate the way GIT works, so I only use it minimally and don't get wrapped up trying to change their goofy model.

Don't worry. Be happy! :grinning:

What don't you like about the way Git works, and is there a version control system you prefer? Just curious.

I've use SVN. Server is a Pi3 with SSD on my LAN. Turtle on the pc.

It is very easy to save daily versions.