verhalten von defines in C

OP #8027007
Lesenswert?

Hallo, ich habe eine Verständinsfrage zu defines in C.

1
#define TYPE               "ABC"
2
#define VARIATION          "_2"
3
#define MAJOR_VERSION      "00"
4
#define MINOR_VERSION      "900"
5
#define SUB_REVISION       "00"
6

7
#define VERSION_STRING TYPE "." VARIATION "." MAJOR_VERSION "." MINOR_VERSION "." SUB_REVISION
8

9

10
... ... ...
11
... ... ...
12

13
char version = VERSION_STRING;
14

15
... ... ...

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
char version = "ABC._2.00.900.00"

oder 2) steht das Define irgendwo im Speicher? Und version zeigt darauf?

(Firma: Golden Delicious Computers) #8027043
Lesenswert?

Der C-Präprozessor ersetzt in einer ersten Runde:

1
char version[20] = VERSION_STRING;

durch

1
char version[20] = TYPE "." VARIATION "." MAJOR_VERSION "." MINOR_VERSION "." SUB_REVISION;

und in einer zweiten durch

1
char version[20] = "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.

: Bearbeitet durch User
#8027046
Lesenswert?

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
char version[] = "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"

: Bearbeitet durch User
#8027047
Lesenswert?

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.

Moderator Persönliche Seite #8027053
Lesenswert?

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.

: Bearbeitet durch Moderator
#8027204
Lesenswert?

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.

: Bearbeitet durch User
Persönliche Seite #8027235
Lesenswert?

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
> char version = "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
char version = "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
char version = "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.

#8027264
Lesenswert?

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)

: Bearbeitet durch User
#8027295
Lesenswert?

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren