I am currently updating the C ++ library for Arduino (especially 8-bit AVR processors compiled using avr-gcc).
Typically, authors of Arduino libraries by default include an external variable for the class inside the header, which is also defined in the class's .cpp file. I assume that basically everything is ready for beginners as inline objects.
Scenario I have: The library I updated no longer requires a .cpp file, and I deleted it from the library. Only after I went to the final pass, checking for errors that I understood, did not cause a linker error, despite the fact that the definition was not specified for the extern variable in the .cpp file.
It is as simple as I can get it (header file):
struct Foo{ void method() {} }; extern Foo foo;
Including this code and using it in one or more source files does not cause any linker error. I tried this on both versions of GCC, which Arduino uses (4.3.7, 4.8.1) and with C ++ 11 on / off.
In an attempt to cause an error, I found that this is possible only when doing something like the address of the address or changing the contents of the added dummy variable.
After discovering this, I consider it important to note:
- Class functions return only other objects, as in, nothing like operators returning references to themselves or even copies.
- It only modifies external objects (registers that are effectively
volatile uint8_t references in the code), and returns temporary classes of other classes. - All class functions in this header are so basic that they cost less than or equal to the cost of calling the function, so they (in my tests) are completely embedded in the caller. A typical operator can create many temporary objects in a call chain, but the compiler sees through them and displays effective registers that change the code, rather than a set of nested function calls.
I also recall reading in n3797 7.1.1 - 8 , which extern can be used on incomplete types, however the class is fully defined, while the declaration is not (this probably doesn't matter).
I am convinced that this may be the result of optimization in the game. I saw an effect that takes an address on objects that would otherwise be considered permanent and compiled without using RAM. Adding any layer of indirection to an object in which the compiler cannot guarantee the state will result in the loss of RAM.
So, perhaps I answered my question simply by asking it, however, I am still making assumptions, and this bothers me. After a fairly lengthy C ++ hobby coding, literally the only thing on my do-not list is making assumptions.
In fact, I want to know:
- As for the working solution that I have, is this a simple case of documenting the inability to accept the address (cause indirectness) of a class?
- Is this just edge-related behavior caused by optimizations that eliminate the need to link something?
- Or simple and simple undefined behavior. How can there be an error in GCC and resolve a code that may fail if the optimization has been reduced or disabled?
Or one of you may be lucky that you have a decoder ring in which you can find a suitable paragraph in the standard that describes the specifics.
This is my first question, so let me know if you want to know some details, I can also provide GitHub links to the code, if necessary.
Edit: Since the library must be compatible with existing code, I need to support the ability to use dot syntax, otherwise I would just have a class of static functions.
To remove the assumptions at the moment, I see two options:
- Add .cpp only to declare a variable.
- Use a definition in the header, such as
#define foo (Foo()) , to use the point syntax through a temporary one.
I prefer a method using the definition of what the community thinks?
Greetings.