Estou interessado em onde literais de seqüência de caracteres são alocados / armazenados.
Eu encontrei uma resposta intrigante aqui , dizendo:
Definir uma string embutida na verdade incorpora os dados no próprio programa e não pode ser alterado (alguns compiladores permitem isso por um truque inteligente, não se preocupe).
Mas, tinha a ver com C ++, sem mencionar que diz para não se preocupar.
Estou incomodando. = D
Então, minha pergunta é onde e como minha string literal é mantida? Por que não devo tentar alterá-lo? A implementação varia de acordo com a plataforma? Alguém quer elaborar o "truque inteligente"?
fonte
foo = "hello"
, neste caso) pode causar efeitos colaterais indesejados ... (supondo que você não alocação de memória comnew
ou algo)char *p = "abc";
para criar seqüências de caracteres mutáveis, como dito de forma diferente por @ChrisCooperNão há uma resposta para isso. Os padrões C e C ++ dizem apenas que os literais de cadeia de caracteres têm duração estática de armazenamento, qualquer tentativa de modificá-los oferece um comportamento indefinido, e vários literais de cadeia de caracteres com o mesmo conteúdo podem ou não compartilhar o mesmo armazenamento.
Dependendo do sistema para o qual você está escrevendo e dos recursos do formato de arquivo executável usado, eles podem ser armazenados junto com o código do programa no segmento de texto ou podem ter um segmento separado para os dados inicializados.
A determinação dos detalhes também varia dependendo da plataforma - provavelmente incluem ferramentas que podem lhe dizer onde está sendo colocada. Alguns até dão a você controle sobre detalhes como esse, se você desejar (por exemplo, o gnu ld permite que você forneça um script para contar tudo sobre como agrupar dados, códigos, etc.)
fonte
movb $65, 8(%esp); movb $66, 9(%esp); movb $0, 10(%esp)
para a string"AB"
, mas na grande maioria das vezes, ele estará em um segmento que não seja de código, como.data
ou.rodata
ou algo semelhante (dependendo se o destino suporta ou não segmentos somente leitura).Por que não devo tentar alterá-lo?
Porque é um comportamento indefinido. Citação do projeto C99 N1256 6.7.8 / 32 "Inicialização" :
Onde eles vão?
GCC 4.8 x86-64 ELF Ubuntu 14.04:
char s[]
: pilhachar *s
:.rodata
seção do arquivo de objeto.text
seção do arquivo de objeto é despejada, com permissões de leitura e execução, mas não gravaçãoPrograma:
Compilar e descompilar:
A saída contém:
Portanto, a string é armazenada na
.rodata
seçãoEntão:
Contém (simplificado):
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[]
:nós obtemos:
para que seja armazenado na pilha (em relação a
%rbp
) e, é claro, podemos modificá-lo.fonte
Para sua informação, basta fazer o backup das outras respostas:
O padrão: ISO / IEC 14882: 2003 diz:
fonte
O gcc cria uma
.rodata
seção que é mapeada "em algum lugar" no espaço de endereço e é marcada como somente leitura,Visual C ++ (
cl.exe
) cria uma.rdata
seção para o mesmo propósito.Você pode ver a saída de
dumpbin
ouobjdump
(no Linux) para ver as seções do seu executável.Por exemplo
fonte
printf("some null terminated static string");
vez deprintf(*address);
em C) #Depende do formato do seu executável . Uma maneira de pensar sobre isso é que, se você estivesse programando uma montagem, poderia colocar literais de string no segmento de dados do seu programa de montagem. Seu compilador C faz algo assim, mas tudo depende de qual sistema você está sendo compilado.
fonte
Literais de seqüência de caracteres são freqüentemente alocados para a memória somente leitura, tornando-os imutáveis. No entanto, em alguns compiladores, a modificação é possível por um "truque inteligente". E o truque inteligente é "usando o ponteiro de caractere apontando para a memória". Lembre-se de alguns compiladores, pode não permitir isso .. Aqui está a demonstração
fonte
Como isso pode diferir de compilador para compilador, a melhor maneira é filtrar um dump de objeto para o literal da cadeia de caracteres pesquisada:
onde
-s
obrigaobjdump
a exibir o conteúdo completo de todas as seções,main.o
é o arquivo do objeto,-B 1
obrigagrep
também a imprimir uma linha antes da partida (para que você possa ver o nome da seção) estr
é a literal da string que você está procurando.Com o gcc em uma máquina Windows e uma variável declarada
main
comocorrida
retorna
fonte