Operator definieren - wie?

Hallo allerseits!

Ich habe eine Struktur, für die ich den ==-Operator definieren möchte:

struct Time
{
  byte hour, minute, second;
};

bool operator==(Time a, Time b)
{
  if(a.hour==b.hour &&
     a.minute==b.minute &&
     a.second==b.second)
   { return(true); }
   else
   { return(false); }
}

Mit diesem Code bekomme ich jedoch eine Fehlermeldung:

/tmp/arduino_build_447005/sketch/growBox.cpp.o (symbol from plugin): In function `operator==(Time, Time)':
(.text+0x0): multiple definition of `operator==(Time, Time)'
/tmp/arduino_build_447005/sketch/211208_Havarie_neuschrieb_0_3.ino.cpp.o (symbol from plugin):(.text+0x0): first defined here
collect2: error: ld returned 1 exit status

Ich kann in meinem Code keinen Fehler entdecken - der ist ja auch sehr simpel. Habe ich wieder einmal mit irgendeiner Arduino-„Spezialität“ zu tun? Kann ich auf andere Art dafür sorgen, dass ich zwei Exemplare dieser Strukturen auf Gleichheit testen kann?

Wichtig ist mir vor Allem, kurzen Code schreiben zu können.

Danke vorweg

Gregor

Sketch uses 444 bytes (1%) of program storage space. Maximum is 32256 bytes.
Global variables use 9 bytes (0%) of dynamic memory, leaving 2039 bytes for local variables. Maximum is 2048 bytes.

compiliert in einem vollständigen Sketch.

aber ein
memcmp(&a, &b, sizeof(struct foo))
würd' das für 3 byte vermutlich auch machen.

Richtig, aber ein Vergleich à la
if(startZeit==aktuelleZeit)
ist wesentlich verständlicher, finde ich.

Gruß

Gregor

zwei fachliche "Probleme" können sich trotzdem ergeben:

  • vieleicht will man so eine if nur einmal pro Sekunde auf true haben
  • solltest du die passende Sekunde verpennen, willst vermutlich trotzdem einmal was auslösen obwohls schon aktuelleZeit+1sec ist ...

Da hast Du recht, für diese Fälle ist aber im aktuellen Code vorgesorgt - er funktioniert problemlos, ich möchte ihn lediglich lesbarer/kürzer gestalten.

Gruß

Gregor

Hoppla ...

Wenn ich die Definition des ==-Operators nicht in einer Headerdatei sondern im „Hauptsketch“ schreibe, funktioniert es. Seltsam.

Gruß

Gregor

#include <Streaming.h> // die Lib findest du selber ;-)
Print &cout = Serial; // cout Emulation für "Arme"


struct Time
{
  byte hour, minute, second;
  bool operator==(Time &b)
  {
    // cout << __FUNCTION__  << endl;
    return  hour    == b.hour &&
            minute  == b.minute &&
            second  == b.second ;
  }
};


void setup()
{
  Serial.begin(9600);
  cout << F("Start: ") << F(__FILE__) << endl;
  Time t1{3, 5, 6};
  Time t2{6, 7, 8};
  cout << (t1 == t2) << endl;
  cout << (t1 == t1) << endl;
}

void loop()
{
}

-------------------

Disclaimer:

  • Dieses ist ein typisches "Combie Posting".
  • Es kann Spuren von Wahnsinn enthalten
  • Es kann Anstoßpunkte für Irritationen, Ungenauigkeiten und Irrtümer enthalten.
  • Es wird dringendst dazu aufgefordert, die evtl. gegebenen Informationen, vor der Verwendung, pingelig zu überprüfen.
  • Es enthält keinerlei Zwang, den Vorschlägen/Gedanken zu folgen.
  • Wem dieses Posting nicht schmeckt, darf es einfach im Regal liegen lassen.
  • Es gibt keine Gewähr für die Funktion der evtl. gegebenen Tipps und/oder den Erhalt der geistigen Gesundheit des Gegenüber.

ja das passiert, wenn man nur code fragmente postet ... :wink:

Ist es nicht!
Die Fehlermeldung des Linkers ist eindeutig.

Jedes mal, wenn du den Operator (die *.h Datei) einbindest wird einer im Programm verankert.

Alternativ:

inline bool operator==(Time a, Time b)
{
  if(a.hour==b.hour &&
     a.minute==b.minute &&
     a.second==b.second)
   { return(true); }
   else
   { return(false); }
}

Dann klappts auch in *.h Dateien.

-------------------

Disclaimer:

  • Dieses ist ein typisches "Combie Posting".
  • Es kann Spuren von Wahnsinn enthalten
  • Es kann Anstoßpunkte für Irritationen, Ungenauigkeiten und Irrtümer enthalten.
  • Es wird dringendst dazu aufgefordert, die evtl. gegebenen Informationen, vor der Verwendung, pingelig zu überprüfen.
  • Es enthält keinerlei Zwang, den Vorschlägen/Gedanken zu folgen.
  • Wem dieses Posting nicht schmeckt, darf es einfach im Regal liegen lassen.
  • Es gibt keine Gewähr für die Funktion der evtl. gegebenen Tipps und/oder den Erhalt der geistigen Gesundheit des Gegenüber.

Jetzt fällt mir doch glatt die Kinnlade runter... Ich dachte immer, inline sei eine Empfehlung, der der Compiler nicht folgen muss und ändere nicht die Sichtbarkeit der Funktion?

[Edit] Hab's gefunden:

There may be more than one definition of an inline function or variable (since C++17) in the program as long as each definition appears in a different translation unit and (for non-static inline functions and variables (since C++17)) all definitions are identical. For example, an inline function or an inline variable (since C++17) may be defined in a header file that is #include'd in multiple source files.

Man sollte doch immer wieder die Specs lesen...

Mir auch.
Denn dann war mein Tipp ja doch nicht ganz richtig, da unser Gregor sicherlich noch mit C++11 unterwegs ist. Das C++17 war mir durch die Lappen gegangen, bin selber meinst mit C++20 unterwegs.

-------------------

Disclaimer:

  • Dieses ist ein typisches "Combie Posting".
  • Es kann Spuren von Wahnsinn enthalten
  • Es kann Anstoßpunkte für Irritationen, Ungenauigkeiten und Irrtümer enthalten.
  • Es wird dringendst dazu aufgefordert, die evtl. gegebenen Informationen, vor der Verwendung, pingelig zu überprüfen.
  • Es enthält keinerlei Zwang, den Vorschlägen/Gedanken zu folgen.
  • Wem dieses Posting nicht schmeckt, darf es einfach im Regal liegen lassen.
  • Es gibt keine Gewähr für die Funktion der evtl. gegebenen Tipps und/oder den Erhalt der geistigen Gesundheit des Gegenüber.

Ich glaube doch, denn der C++17-Zusatz bezieht sich auf die Ausweitung auf inline Variable.

C++20 ist mir bisher zu abstrakt, da muss ich mich erst noch eingrooven.

Hallo,

das ändert jedoch nichts an der inline Empfehlung gegenüber dem Compiler. Diese Empfehlung ist immer noch gültig. In dem Zitat geht es um die Sichtbarkeit von Definitionen.

Sichtbarkeit ist hier nicht das richtige Wort, denn die ändert sich nicht durch inline.

-------------------

Disclaimer:

  • Dieses ist ein typisches "Combie Posting".
  • Es kann Spuren von Wahnsinn enthalten
  • Es kann Anstoßpunkte für Irritationen, Ungenauigkeiten und Irrtümer enthalten.
  • Es wird dringendst dazu aufgefordert, die evtl. gegebenen Informationen, vor der Verwendung, pingelig zu überprüfen.
  • Es enthält keinerlei Zwang, den Vorschlägen/Gedanken zu folgen.
  • Wem dieses Posting nicht schmeckt, darf es einfach im Regal liegen lassen.
  • Es gibt keine Gewähr für die Funktion der evtl. gegebenen Tipps und/oder den Erhalt der geistigen Gesundheit des Gegenüber.

Hallo,

ja okay, man kann das nicht so runterbrechen. Der Compiler muss eine inline Definition erst im Header sehen damit er sie inlinen kann, womit sie dann "weg" ist und damit nicht mehr "sichtbar" ist. Wobei man kurz denken könnte muss eigentlich sichtbar sein, weil steht ja im Header. Guckste isse weg. Die Wirkung muss hier beachtet werden. Ihr wisst ja Bescheid. :wink:

Der Compiler macht sie nicht "weg"

Der Compiler sieht die Funktion
Er reicht sie weiter an den Linker, damit dieser sie Linken kann
Der Linker sieht einen Haufen Funktionen mit dem gleichen Namen.
Wenn diese alle das Attribut inline haben, dann schmeißt er alle bis auf eine weg.
Also: Alle Übersetzungseinheiten teilen sich, bzw. nutzen, die gleiche+identische Funktion

Du meinst sicherlich die Wirkung des Attribut static auf Funktionen/Variablen in *.h Dateien.
Da hat dann jede einzelne Übersetzungseinheit seine eigene Instanz

Bedenke:
Alle Funktionen mit inline Attribut und mit gleichen Namen müssen die identische Definition haben, sonst landet man im Undefined Behavior

Bei statischen Funktionen, mit gleichen Namen, kann jede Übersetzungseinheit seine eigene Variante haben.

-------------------

Disclaimer:

  • Dieses ist ein typisches "Combie Posting".
  • Es kann Spuren von Wahnsinn enthalten
  • Es kann Anstoßpunkte für Irritationen, Ungenauigkeiten und Irrtümer enthalten.
  • Es wird dringendst dazu aufgefordert, die evtl. gegebenen Informationen, vor der Verwendung, pingelig zu überprüfen.
  • Es enthält keinerlei Zwang, den Vorschlägen/Gedanken zu folgen.
  • Wem dieses Posting nicht schmeckt, darf es einfach im Regal liegen lassen.
  • Es gibt keine Gewähr für die Funktion der evtl. gegebenen Tipps und/oder den Erhalt der geistigen Gesundheit des Gegenüber.

Hmm. Ja, es wird der gleiche Code sein - aber kein Funktionsaufruf mehr.
In dem von uns bevorzugten C++-Buch Seite 146:

The inline keyword does have meaning, but not the meaning you may expect. It doesn't mean that the compiler must/should/might inline expand the function, that the compiler may decide to do as it sees fit, no matter if you use inline or not.

What it does mean is that you should and could repeat the function definition in every compilation unit where it is used, without resulting in linking errors - quite similar to the static keyword.

For example GCC 4.7.2 (which is perhaps not state-of-the-art, but still quite a modern compiler) seem to interpret inline no more than the standard specifies. It does not seem to inline the function if optimization is disabled and with optimization turned on it seem to inline as it likes anyway. The only difference is how the compiler handles the "outlined" function in the different cases, with inline it simply discard it or handles it in a way that would avoid duplicate symbols at link time.

inline ist also primär für die Sichtbarkeit, sekundär auch ein Hinweis an den Compiler, dass sich ein vermiedener Call lohnen könnte. Was der Compiler daraus macht, ist seine Sache...

Das hat nichts mit dem zu tun, was ich gesagt habe und auch nichts mehr (kaum noch was?) mit dem Schlüsselwort inline. Sondern das ist das default Verhalten der modernen Compiler+Linker Kombi bei aktivierter Optimierung. Ob und wie er das tut, ist seine Sache.

Das inline Schlüsselwort verhindert "multiple definition of" Meldungen des Linkers. Und das unabhängig von der Optimierungsstufe.

Wenn das Buch nicht alle Aspekte moderner Toolchains abhandelt, dann ist das schade.
Aber leider nicht zu ändern.

-------------------

Disclaimer:

  • Dieses ist ein typisches "Combie Posting".
  • Es kann Spuren von Wahnsinn enthalten
  • Es kann Anstoßpunkte für Irritationen, Ungenauigkeiten und Irrtümer enthalten.
  • Es macht keinen Versuch vollständig sein zu wollen.
  • Es wird dringendst dazu aufgefordert, die evtl. gegebenen Informationen, vor der Verwendung, pingelig zu überprüfen.
  • Es enthält keinerlei Zwang, den Vorschlägen/Gedanken zu folgen.
  • Wem dieses Posting nicht schmeckt, darf es einfach im Regal liegen lassen.
  • Es gibt keine Gewähr für die Funktion der evtl. gegebenen Tipps und/oder den Erhalt der geistigen Gesundheit des Gegenüber.