Der Martin: C , Zeigerzugriff

Beitrag lesen

Hallo Stefanie,

»» Schreibt man in C eine Zeichenkette in doppelten Anführungszeichen, wird diese zunächst in der compilierten Programmdatei irgendwohin hard-codiert

das ist soweit erstmal richtig.

»» Beim Ausführen des Programms gelangt dieser String zusammen mit dem Maschinencode des Executables in einen schreibgeschützten Bereich

Üblicherweise liegt er da von Anfang an.

Ich denke, Du meinst den Code-Bereich? Die Daten des Strings stehen so gesehen mit im Programmcode drin, das stimmt. Und der Code kann nie geändert werden.

Doch, kann er - und das ist nicht nur betriebssystemabhängig. Denk mal an Debugger, die ja auch den zu untersuchenden Code im Codesegment manipulieren, z.B. Breaks hineinschreiben oder gar CPU-Instruktionen auf Wunsch des Anwenders (Programmierers) verändern.
Und selbstmodifizierender Code ist auch immer noch ein heißes Thema bei den hirnkranken Programmierern von Viren. Virenscanner arbeiten oft so, dass sie den Code nach bestimmten, typischen Bytefolgen (Signaturen) absuchen. Um der Erkennung zu entgehen, wird der fertige Maschinencode oft nochmal verschlüsselt und erst zur Laufzeit wieder entschlüsselt.

Es wäre jedoch denkbar, dass es Compiler-abhängig ist, wie diese Daten im Code abgelegt sind.

Ja. Es ist aber durchaus gängige Praxis, dass Stringkonstanten direkt im Codesegment abgelegt werden, anstatt im Datensegment für initialisierte Variablen. Bei manchen Compilern kann man das per Compiler-Direktive auch steuern, wenn man eine bestimmte Anordnung unbedingt haben will.

Der Compiler hat die Anweisung, eine Folge von Bytes an einen bestimmten Speicher zu kopieren. Letztlich tut er das ja mit einzelnen Schreibbefehlen für jedes einzelne Byte oder Wort, und das könnte er auch ohne, dass er den gesamten String vorher zusammenhängend ablegt.

Theoretisch. Das wäre aber höchst ineffizient.

»» Die Variable 'bla' im obigen Beispiel enthält dann die Anfangsadresse dieses hardcodierten Strings,
...der tatsächlich im Code-Bereich liegt? Und dahinter liegen die kompletten Bytes des Strings?

Üblicherweise ja.

Finde ich interessant. Dann stimmt so gesehen Deine Aussage, der String wäre schreibgeschützt. Denn lesend müssten man ja drauf zugreifen können.

Richtig.

Trotzdem sollte man es wohl besser unterlassen, seine Daten im Code abzulegen, um damit zu arbeiten...

Selbstverständlich. Man muss da auch etwas genauer unterscheiden.

1. Deklaration mit char[]:
Beispiel:   char[] str = "String für Beispiel 1";
Hier kommt es noch darauf an, ob diese Definition innerhalb einer Funktion erfolgt (lokal), oder ob sie im globalen Scope steht.
Ist sie lokal, dann wird das gesamte Array beim Eintritt in die Funktion (typischerweise auf dem Stack) angelegt und initialisiert. Der Initialisierungsstring liegt in der Regel als Stringkonstante im Codesegment und wird beim Eintritt in die Funktion umkopiert. Bei jedem Eintritt in die Funktion hat man wieder einen frisch initialisierten String, auch wenn er beim vorherigen Funktionsaufruf modifiziert wurde, denn man arbeitet ja immer nur mit einer neuen Kopie.
Ist sie global, dann wird das Array bereits vom Compiler im Datensegment für initialisierte Daten angelegt und initialisiert. Veränderungen am String-Inhalt sind in diesem Fall permanent.
Unabhängig davon, ob lokal oder global, wird kein Zeiger namens str angelegt! Es ist also möglich, auf str[x] zu schreiben, aber nicht auf str direkt, d.h. ein str = NULL; wird fehlschlagen.

2. Deklaration mit char*:
Beispiel:   char* str = "String für Beispiel 2";
In diesem Fall wird tatsächlich eine Zeigervariable namens str angelegt. Ob der Initialiserungsstring im Daten- oder im Codesegment abgelegt wird, ist compilerabhängig bzw. kann durch Einstellungen vorgegeben werden. Liegt der String im Codesegment, kann auf die einzelnen Zeichen nicht schreibend zugegriffen werden. Ein Schreibzugriff auf den Zeiger str ist aber sehr wohl möglich! Ein nachfolgendes str = NULL; wäre also vermutlich nicht sinnvoll, aber zulässig.

3. Stringkonstanten, die nicht mit Variablen referenziert werden
Beispiel:   printf("Hallo Welt!");
Reine Stringkonstanten, die mit keiner Variablen in Verbindung gebracht werden, legt der Compiler in der Regel im Codesegment ab, da sowieso keine Chance besteht, auf diese Daten schreibend zuzugreifen.

Bei Deiner Aufzählung von veränderlichen Speicherbereichen hast Du übrigens den Datenbereich vergessen.

Jein - er hat den Heap erwähnt, den man mit gutem Willen als solchen interpretieren darf. ;-)

Ciao,
 Martin

--
Ist die Katze gesund,
freut sich der Hund.