Warum sollte ich nicht versuchen, es zu ändern?
Weil es undefiniertes Verhalten ist. Zitat aus C99 N1256 Entwurf 6.7.8 / 32 "Initialisierung" :
BEISPIEL 8: Die Erklärung
char s[] = "abc", t[3] = "abc";
definiert "einfache" char-Array-Objekte sundt deren Elemente mit Zeichenfolge Literale initialisiert.
Diese Erklärung ist identisch mit
char s[] = { 'a', 'b', 'c', '\0' },
t[] = { 'a', 'b', 'c' };
Der Inhalt der Arrays kann geändert werden. Auf der anderen Seite die Erklärung
char *p = "abc";
definiert pmit dem Typ "Zeiger auf Zeichen" und initialisiert es so, dass es auf ein Objekt mit dem Typ "Array von Zeichen" mit der Länge 4 zeigt, dessen Elemente mit einem Zeichenfolgenliteral initialisiert werden. Wenn versucht wird, pden Inhalt des Arrays zu ändern, ist das Verhalten undefiniert.
Wohin gehen sie?
GCC 4.8 x86-64 ELF Ubuntu 14.04:
char s[]: Stapel
char *s::
.rodata Abschnitt der Objektdatei
- Das gleiche Segment, in dem der
.textAbschnitt der Objektdatei ausgegeben wird, der über Lese- und Ausführungsberechtigungen verfügt, jedoch nicht über Schreibberechtigungen
Programm:
#include <stdio.h>
int main() {
char *s = "abc";
printf("%s\n", s);
return 0;
}
Kompilieren und dekompilieren:
gcc -ggdb -std=c99 -c main.c
objdump -Sr main.o
Die Ausgabe enthält:
char *s = "abc";
8: 48 c7 45 f8 00 00 00 movq $0x0,-0x8(%rbp)
f: 00
c: R_X86_64_32S .rodata
Der String wird also im gespeichert .rodata Abschnitt .
Dann:
readelf -l a.out
Enthält (vereinfacht):
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x0000000000000704 0x0000000000000704 R E 200000
Section to Segment mapping:
Segment Sections...
02 .text .rodata
Dies bedeutet, dass das Standard-Linker-Skript sowohl .textals auch .rodatain ein Segment kopiert, das ausgeführt, aber nicht geändert werden kann (Flags = R E ). Der Versuch, ein solches Segment zu ändern, führt unter Linux zu einem Segfault.
Wenn wir dasselbe tun für char[]:
char s[] = "abc";
wir erhalten:
17: c7 45 f0 61 62 63 00 movl $0x636261,-0x10(%rbp)
so wird es im Stapel gespeichert (relativ zu %rbp), und wir können es natürlich ändern.