Por que não devo tentar alterá-lo?
Porque é um comportamento indefinido. Citação do projeto C99 N1256 6.7.8 / 32 "Inicialização" :
EXEMPLO 8: A declaração
char s[] = "abc", t[3] = "abc";
define objetos de matriz de caracteres "simples" s
e t
cujos elementos são inicializados com literais de cadeia de caracteres.
Esta declaração é idêntica à
char s[] = { 'a', 'b', 'c', '\0' },
t[] = { 'a', 'b', 'c' };
O conteúdo das matrizes é modificável. Por outro lado, a declaração
char *p = "abc";
define p
com o tipo "ponteiro para char" e o inicializa para apontar para um objeto com o tipo "array of char" com comprimento 4 cujos elementos são inicializados com uma cadeia de caracteres literal. Se for feita uma tentativa p
de modificar o conteúdo da matriz, o comportamento será indefinido.
Onde eles vão?
GCC 4.8 x86-64 ELF Ubuntu 14.04:
char s[]
: pilha
char *s
:
.rodata
seção do arquivo de objeto
- o mesmo segmento em que a
.text
seção do arquivo de objeto é despejada, com permissões de leitura e execução, mas não gravação
Programa:
#include <stdio.h>
int main() {
char *s = "abc";
printf("%s\n", s);
return 0;
}
Compilar e descompilar:
gcc -ggdb -std=c99 -c main.c
objdump -Sr main.o
A saída contém:
char *s = "abc";
8: 48 c7 45 f8 00 00 00 movq $0x0,-0x8(%rbp)
f: 00
c: R_X86_64_32S .rodata
Portanto, a string é armazenada na .rodata
seção
Então:
readelf -l a.out
Contém (simplificado):
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
Isso significa que o script do vinculador padrão despeja ambos .text
e .rodata
em um segmento que pode ser executado, mas não modificado ( Flags = R E
). Tentar modificar esse segmento leva a um segfault no Linux.
Se fizermos o mesmo para char[]
:
char s[] = "abc";
nós obtemos:
17: c7 45 f0 61 62 63 00 movl $0x636261,-0x10(%rbp)
para que seja armazenado na pilha (em relação a %rbp
) e, é claro, podemos modificá-lo.