Ich habe jetzt zwei Verschieden Möglichkeiten gehört. Und bin mir nicht
sicher was jetzt richtig ist.
1) Wird das define beim Compilieren direkt ersetzen?
Also steht dann dort quasi
1
charversion="ABC._2.00.900.00"
oder
2) steht das Define irgendwo im Speicher? Und version zeigt darauf?
Moin,
Ich tendiere stark zu deiner Moeglichkeit 1 und erhoehe um Probleme, die
du kriegst, weil in einen char nur ein Zeichen passt und kein ganzer
String.
Gruss
WK
Chandler B. schrieb:> 1) Wird das define beim Compilieren direkt ersetzen?
Der Präprozessor löst die Defines und Includes auf.
Danach kommt der Compiler dran.
Chandler B. schrieb:> 2) steht das Define irgendwo im Speicher?
Nicht das Define, aber der String wird sich in irgendeinem Speicher
befinden.
Dergute W. schrieb:> und erhoehe um Probleme, die> du kriegst, weil in einen char nur ein Zeichen passt und kein ganzer> String.
Das ist richtig.
Sollte
1
charversion[20]=VERSION_STRING;
Arduino F. schrieb:> Nicht das Define, aber der String wird sich in irgendeinem Speicher> befinden.
Der String an für sich? Oder der String in der Variablen version?
Chandler B. schrieb:> Der String an für sich? Oder der String in der Variablen version?
Der String steht irgendwo im Speicher. Die Variable verweist darauf.
#defines die nicht verwendet werden, werden einfach ignoriert, weil sie
... nicht verwendet werden.
Chandler B. schrieb:> Wird das define beim Compilieren direkt ersetzen?> Also steht dann dort quasi
Es Wird ersetzt durch
char version = "ABC" "." "_2" "." "00" "." "900" "." "00";
Das wird dann an den eigentlichen C-Compiler weitergegeben.
Der weiss dass zwei hintereinander stehende Strings zusammengesetzt
werden sollen. Also ist das identisch zu:
1
char version[20] = "ABC._2.00.900.00";
Das versteht der Compiler nun so, dass er im Speicher 20 Bytes
reserviert und mit den Zeichen ABC._2.00.900.00 vorbelegt.
Also gehört der String zum Programmspeicher und steht dann bei der
Ausführung im Speicher. Und "version" verweist auf die Speicheradresse,
so dass z.B. version[5] eine '2' ergibt.
Die defines werden einfach ersetzt durch das, als was sie definiert
wurden.
Jag es einfach mal durch den Präprozessor, dann siehst du, daraus wird:
https://godbolt.org/z/GYErcPzGP
1
charversion[]="ABC"".""_2"".""00"".""900"".""00";
Mehrere String literale nacheinander werden dann vom Compiler wie ein
einzelnes behandelt. Ist recht praktisch, haben diverse andere Sprachen
auch so übernommen, und dort gibt es oft mehrere Arten String-literale
zu schreiben.
C++: "A" R"X(B)X" entspricht "AB"
python: "test" 'abc' f"{123}" entspricht "testabc123"
bash: "A"'B'C entspricht "ABC"
Chandler B. schrieb:> Wird das define beim Compilieren direkt ersetzen?
Nein, der Code wird zuerst beispielsweise wie mit der Suchfunktion im
VI-Editor angepasst. Auf diese Weise kann man Makro-Szenarien erstellen,
welche die Programmierung erleichtern, (oder ihn besser Dokumentieren,
LOL) oder Konstanten wie Mathematische Fix-Zahlen (wie PI) einfliegen.
Zu Anfangszeiten von C meinten auch einige, mit Hilfe dieser
Vorkau-Steuerung C wieder zurück nach Assembler zu frisieren. In
Assembler sind ja auch Makros nicht standardisiert, wo man sich dann
über Dialekte wundern kann.
Nick schrieb:> Die Variable verweist darauf.
Nicht ganz. So, wie es da steht, ist es ja echt eine Variable, also
etwas, was zur Laufzeit geändert werden kann.
Damit steht der String irgendwo (read-only) im Speicher. Beim Start des
Programms wird er von da in die Variable kopiert, steht also alles in
allem dann zweimal im Speicher.
Aber das hat natürlich jetzt nichts (mehr) mit dem preprocessing zu tun.
Der Präprozessor war früher oft ein eigenes Programm, heute ist er es
meist nicht mehr. Spielt aber für seine Funktionsweise jetzt keine
Rolle.
Jörg W. schrieb:> Damit steht der String irgendwo (read-only) im Speicher. Beim Start des> Programms wird er von da in die Variable kopiert, steht also alles in> allem dann zweimal im Speicher.
Ja, gut. OK!
Hätte er halt const char[] schreiben sollen. ;-)
Nick schrieb:> Hätte er halt const char[] schreiben sollen. ;-)
Es ist implementation Defined, wo der String dann landet.
z.B. bei den alten AVR wird er trotz const ins RAM kopiert.
Da aufgeteile Adressierung RAM vs Flash vs EEPROM
Arduino F. schrieb:> s ist implementation Defined, wo der String dann landet.
OK, mag so sein.
Ich könnte aber auch argumentieren, dass der Compiler merkt, dass der
Versionsstring nie verändert wird und daher im ROM steht. Das ist
sicherlich auch Compilerabhängig.
Und nein, ich widerspreche nicht Jörg W.
Nick schrieb:> Das ist sicherlich auch Compilerabhängig.
Insbesondere ist es eben architekturabhängig.
Wenn du (wie beim klassischen AVR) für den Zugriff auf den ROM andere
Befehle als für den Zugriff auf den RAM brauchst, musst du u.U. Dinge im
RAM ablegen, damit hernach sowas wie strcpy() funktioniert.
Arduino F. schrieb:> Aber dann musst du es auf dem AVR auch richtig machen.
Die Frage war aber nicht spezifisch für den AVR. Also interessiert hier
nur der Standard.
Die Sonderlocke __flash mag zwar für den AVR richtig sein, aber hier
argumentativ nicht relevant.
Nick schrieb:> Also interessiert hier> nur der Standard.
Und du bist hier der Bestimmer.
Oder ist das schon der aktive Rückzug, weil du erwischt wurdest?
Arduino F. schrieb:> Aber dann musst du es auf dem AVR auch richtig machen.const char __flash> version[20] = "ABC" "." "_2" "." "00" "." "900" "." "00";
Die 20 in den eckigen Klammern kann und sollte man weglassen; der
Compiler kann selbst zählen (und berücksichtigt die implizite \0 am
Stringende).
Arduino F. schrieb:> Oder ist das schon der aktive Rückzug, weil du erwischt wurdest?
Wobei erwischt? Wie du den AVR als Erster in die Arena geworfen hast?
Achso, Arduino F. Heißt das "F." "Fanboy"? Das würde Deine beschränkte
Sicht erklären.
Arduino F. schrieb:> Und du bist hier der Bestimmer.
Der TO ist es. Die Frage war komplett plattforumunabhängig gestellt.
Harald K. schrieb:> Die 20 in den eckigen Klammern kann und sollte man weglassen;
Wenn es eine Konstante(read only) ist, dann hast du voll wahr.
Ein paar Beiträge vorher war es noch ein Variable.
Ist mir von da mit durchgerutscht
Nick schrieb:> Achso, Arduino F. Heißt das "F." "Fanboy"?
Jawoll!
Nick schrieb:> Das würde Deine beschränkte> Sicht erklären.
Wenn du meinst...
Wenn du dich damit besser, größer und stärker fühlst.
Ansonsten:
Sach ich ja: Aktiver Rückzug.
Chandler B. schrieb:> 1) Wird das define beim Compilieren direkt ersetzen?
In Translation Phase 4: Preprocessing directives are executed macro
invocations are expanded, and _Pragma unary operator expressions are
executed.
> Also steht dann dort quasi
1
>charversion="ABC._2.00.900.00"
> oder> 2) steht das Define irgendwo im Speicher? Und version zeigt darauf?
Weder noch. Der Präprozessor (Translation Phase 4) macht daraus:
1
charversion="ABC"".""_2"".""00"".""900"".""00";
sieht man zum Beispiel in der präprozessierten Quelle (bei GCC
beispielsweise mit -save-temps in den *.i Files).
Translation Phase 6 macht dann: Adjacent string literal tokens are
concatenated. Entspricht dann:
1
charversion="ABC._2.00.900.00";
Die Diagnostic (Warning / Error), dass einem char ein const char*
zugewiesen wird, wird in Translation Phase 7 ausgegeben: The resulting
tokens are syntactically and semantically analyzed and translated as a
translation unit.
Chandler B. schrieb:> Sollte> char version[20] = VERSION_STRING;
besser ist nur ein ptr:
> const char * const version = VERSION_SRING;
Hier ist "version" einfach nur ein prt auf einen (const) text.
version selbst ist auch konstant, kann also nicht einfach auf einen
anderen Text umgelegt werden.
Und egal ob im Ram oder Rom, normalerweise ist das die Darstellung mit
der geringsten Wahrscheinlichkeit von doppeltem Speicher oder späterer
Änderung.
(Das hat aber alles nichts mehr mit VERSION_STRING oder Präprozessor zu
tun, das wurde zu Anfang gut erläutert)
Nick schrieb:> Also interessiert hier nur der Standard.
Der darüber natürlich nichts aussagt.
Mit "const" könnte man dem Compiler natürlich zumindest auf den
Plattformen, wo es problemlos möglich ist, einen Hinweis geben, dass er
den String nur einmal ablegen muss.
Jörg W. schrieb:> Der darüber natürlich nichts aussagt.
Da sind wir uns also einig. Irgendwelche Ausnahmen oder
Plattformspezifika wurden vom TO nicht gefragt.
Ich find die Frage des TO auch in keiner Weise dumm. Er hat halt
Wissenslücken (hatte jeder mal) und hat in einer klaren Art & Weise
gefragt. Er hat auch gute Antworten dafür bekommen. Nur gibts halt paar
Leute die entweder nicht ordentlich lesen können, oder sich mit ihrem
Nischenwissen hervortun müssen.
Mit dir kann man ja auch auf einer vernünftigen Ebene argumentieren.