Hallo zusammen,
ich möchte die Größe eines Strings auslesen, wird später zur
Weiterverarbeitung benötigt.
#define VERS_PROGRAMVERSION “V01.00.00“ /* Programmversion */
uint8_t temp;
temp = sizeof (VERS_PROGRAMVERSION);
Ist dies mit sizeof zulässig und verlässlich?
Im Simulator und auch auf der HW (ATMEGA64) scheint es zu funktionieren,
es stellt sich allerdings die Frage, ob es hier je nach Compiler-Version
zu bösen Überraschungen kommen kann.
Kann dies jemand beantworten, vorab vielen Dank für eine Rückmeldung.
Grüße
Andreas
sizeof liefert zuverlässig die Länge eines string literal,
einschließlich der 0 am Ende.
strlen liefert die Länge eines string, ohne die 0 am Ende.
Ein weiterer Unterscheid ist, dass strlen nur die Länge bis zur ersten 0
liefert, sizeof beim string literal dagegen die bis zur letzten.
Beispiele:
Andi_T T. schrieb:> jetzt verstehe ich auch die +1 bei sizeof> (habe nicht an die /0) gedacht.
sizeof liefert die Objektgröße im Speicher zurück. Das Objekt String
besteht aus den Zeichen + dem Endzeichen /0.
strlen liefert die Anzahl der Zeichen bis zum Endzeichen /0 zurück.
> ich würde so schreiben.
Stimmt, inzwischen hat sich jeder an const und inline gewöhnt - wenn ich
ein #define sehe, kommt sofort das Vermutung auf, das ist uralter Code,
Altlasten.
berechnet der Prozessor und es braucht Speicherplatz der Länge
sizeof(VERS_PROGRAMVERSION), die in einer Schleife durchgezählt werden.
Der Compiler legt dazu einen unbenannten String im Speicher ab.
1
const char PROGRAMVERSION [] = "V01.00.00";
2
sizeof(PROGRAMVERSION)
berechnet zwar auch der Compiler (weil er die Arraylänge kennt) aber das
braucht trotzdem Speicher... Ausser er kann es wegoptimieren (hängt von
verschiedenen Faktoren ab ob das geht).
Speicher und Rechenzeit spart man also mit der ersten Variante am
meisten.
Noch ein Kommentar schrieb:> Stimmt, inzwischen hat sich jeder an const und inline gewöhnt - wenn ich> ein #define sehe, kommt sofort das Vermutung auf, das ist uralter Code,> Altlasten.
Oder C-Code. Da ist const was völlig anderes.
Nikolaus S. schrieb:> #define VERS_PROGRAMVERSION “V01.00.00“ /* Programmversion */> strlen(VERS_PROGRAMVERSION)> berechnet der Prozessor und es braucht Speicherplatz der Länge> sizeof(VERS_PROGRAMVERSION), die in einer Schleife durchgezählt werden.> Der Compiler legt dazu einen unbenannten String im Speicher ab.
Dann hast du aber einen schlechten Compiler erwischt. Etwas bessere
machen das natürlich auch komplett zur Compilezeit. Beispielsweise der
avr-gcc (da von ATmega die Rede ist):
Rolf M. schrieb:> Wie man sieht, wird die 9 einfach direkt an den Port geschrieben, und> der String kommt überhaupt nicht vor.
Das geht aber nur mit der Vereinbarung, dass strlen keine externe
Funktion.
A. S. schrieb:> Rolf M. schrieb:>> Wie man sieht, wird die 9 einfach direkt an den Port geschrieben, und>> der String kommt überhaupt nicht vor.>> Das geht aber nur mit der Vereinbarung, dass strlen keine externe> Funktion.
Bei einer hosted-Implementation darf der Compiler die Annahme treffen,
dass sich die Funktion strlen() aus <string.h> genau wie im Standard
definiert verhält und auf dieser Basis dann optimieren. Das macht gcc
nicht nur bei strlen(), sondern auch bei sehr vielen weiteren
Standard-Funktionen.
Rolf M. schrieb:> Bei einer hosted-Implementation darf der Compiler die Annahme treffen,> dass sich die Funktion strlen() aus <string.h> genau wie im Standard> definiert verhält und auf dieser Basis dann optimieren.
Genau das hättest Du sofort dazu sagen sollen, statt:
Rolf M. schrieb:> Dann hast du aber einen schlechten Compiler erwischt.
Es ist halt ein Unterschied, ob ein Compiler eine Funktion aufruft oder
dessen Ergebnis ermittelt.
A. S. schrieb:> Es ist halt ein Unterschied, ob ein Compiler eine Funktion aufruft oder> dessen Ergebnis ermittelt.
Ja, sicher. Aber im C-Standard gilt die "as if"-Regel: der Code muss
sich so verhalten, als ob die abstrakte Maschine ihn ausgeführt hätte.
Da die Funktionen der Standardbibliothek genormt sind, darf der Compiler
sein Wissen über diese Funktionen dafür einsetzen, ein vorab bekanntes
Ergebnis eben nicht erst durch den Aufruf der Funktion zu ermitteln,
sondern sofort einzusetzen.
Gute Compiler machen das, wenn man es ihnen nicht ausdrücklich verbietet
(-ffreestanding).
A. S. schrieb:> Es ist halt ein Unterschied, ob ein Compiler eine Funktion aufruft oder> dessen Ergebnis ermittelt.
Ja, der Unterschied liegt in diesem Fall darin, dass letzterer besser
optimiert.
Jörg W. schrieb:> Ja, sicher. Aber im C-Standard gilt die "as if"-Regel: der Code muss> sich so verhalten, als ob die abstrakte Maschine ihn ausgeführt hätte.
Das ist alles klar. Er hätte es nur einfach anmerken sollen. Sonst denkt
der TO, dass es bei anderen Funktionen (die nicht stdlib sind) auch
geht, wenn der Compiler sie kennt. "Weil das bei C++ ja auch geht".
Es ist ein Sonderfall, dann soll man es auch sagen. Oder noch besser,
die Bedingungen erwähnen. Nicht einfach "Dein Compiler ist blöd".
A. S. schrieb:> Jörg W. schrieb:>> Ja, sicher. Aber im C-Standard gilt die "as if"-Regel: der Code muss>> sich so verhalten, als ob die abstrakte Maschine ihn ausgeführt hätte.>> Das ist alles klar. Er hätte es nur einfach anmerken sollen. Sonst denkt> der TO, dass es bei anderen Funktionen (die nicht stdlib sind) auch> geht, wenn der Compiler sie kennt.
Das geht eingeschränkt auch bei solchen Funktionen, allerdings muss der
Compiler dann auch an der Stelle des Aufrufs den Quellcode der Funktion
kennen, denn irgendwo muss er ja die Beschreibung dessen, was sie tut
her bekommen.
Bei den Standardfunktionen muss er den Quellcode prinzipiell nicht
kennen, da er die Beschreibung aus dem Standard hat, den er ja selbst
implementiert. Er darf annehmen, dass sie sich so verhalten, wie der
Standard das vorschreibt.
> "Weil das bei C++ ja auch geht".>> Es ist ein Sonderfall, dann soll man es auch sagen. Oder noch besser,> die Bedingungen erwähnen. Nicht einfach "Dein Compiler ist blöd".
Es ging hier konkret um strlen() im Vergleich zu sizeof und um die
Behauptung , dass strlen() mehr Aufwand an Rechenzeit und Speicher
produziere, weil es zwingend zur Laufzeit ausgeführt werden müsse. Das
stimmt aber nicht, und optimierende Compiler nutzen dieses Potenzial
auch seit vielen Jahren. Und da es hier um AVR geht, habe ich auch
gleich noch für den avr-gcc gezeigt, dass dieser das tut.
Nirgends habe ich behauptet, dass der Compiler sämtliche Funktionen auf
der Welt zur Compilezeit ausführen könne.