Historicamente (talvez reescrevendo partes dela), era o contrário. Nos primeiros computadores do início dos anos 1970 (talvez PDP-11 ) executando um C embrionário prototípico (talvez BCPL ), não havia MMU e nenhuma proteção de memória (que existia na maioria dos mainframes IBM / 360 mais antigos ). Portanto, cada byte de memória (incluindo aqueles que manipulam cadeias literais ou código de máquina) pode ser sobrescrito por um programa incorreto (imagine um programa mudando alguns %
para /
uma cadeia de formato printf (3) ). Portanto, cadeias literais e constantes eram graváveis.
Quando adolescente, em 1975, eu codifiquei no museu Palais de la Découverte em Paris em computadores antigos da década de 1960 sem proteção de memória: o IBM / 1620 tinha apenas uma memória principal - que era possível inicializar através do teclado, e era preciso digitar várias dezenas de dígitos para ler o programa inicial em fitas perfuradas; CAB / 500 tinha uma memória de tambor magnético; você pode desativar a gravação de algumas faixas através de interruptores mecânicos próximos ao tambor.
Mais tarde, os computadores obtiveram algum tipo de unidade de gerenciamento de memória (MMU) com alguma proteção de memória. Havia um dispositivo que proibia a CPU de substituir algum tipo de memória. Portanto, alguns segmentos de memória, principalmente o segmento de código (também conhecido como .text
segmento), tornaram-se somente leitura (exceto pelo sistema operacional que os carregou do disco). Era natural que o compilador e o vinculador colocassem as cadeias literais nesse segmento de código, e as cadeias literais se tornassem somente leitura. Quando seu programa tentou substituí-los, foi um comportamento indefinido . E ter um segmento de código somente leitura na memória virtual oferece uma vantagem significativa: vários processos executando o mesmo programa compartilham a mesma RAM ( memória físicapáginas) para esse segmento de código (consulte o MAP_SHARED
sinalizador para mmap (2) no Linux).
Hoje, os microcontroladores baratos têm alguma memória somente leitura (por exemplo, Flash ou ROM) e mantêm seu código (e as strings literais e outras constantes) lá. E microprocessadores reais (como o do seu tablet, laptop ou desktop) possuem uma sofisticada unidade de gerenciamento de memória e máquinas de cache usadas para memória virtual e paginação . Portanto, o segmento de código do programa executável (por exemplo, no ELF ) é mapeado como um segmento somente leitura, compartilhável e executável (por mmap (2) ou execve (2) no Linux; BTW, você pode fornecer diretrizes para ldpara obter um segmento de código gravável, se você realmente quisesse). Escrever ou abusar geralmente é uma falha de segmentação .
Portanto, o padrão C é barroco: legalmente (apenas por razões históricas), cadeias literais não são const char[]
matrizes, mas somente char[]
matrizes que são proibidas de serem substituídas.
BTW, poucas linguagens atuais permitem que os literais de strings sejam substituídos (mesmo o Ocaml, que historicamente - e mal - possuía strings literais graváveis, mudou esse comportamento recentemente em 4.02, e agora possui strings somente leitura).
Os compiladores C atuais podem otimizar, compartilhar "ions"
e "expressions"
compartilhar seus últimos 5 bytes (incluindo o byte nulo final).
Tente compilar o código C em arquivo foo.c
com gcc -O -fverbose-asm -S foo.c
e olhar dentro do arquivo assembler gerado foo.s
pelo GCC
Por fim, a semântica de C é complexa o suficiente (leia mais sobre o CompCert e o Frama-C, que estão tentando capturá-lo) e a adição de seqüências literais constantes e graváveis tornaria ainda mais misteriosa, tornando os programas mais fracos e menos seguros (e com menos comportamento definido), portanto, é muito improvável que os futuros padrões C aceitem cadeias literais graváveis. Talvez, pelo contrário, eles os fizessem const char[]
matrizes como deveriam ser moralmente.
Observe também que, por muitas razões, os dados mutáveis são mais difíceis de manipular pelo computador (coerência do cache), codificar, entender pelo desenvolvedor, do que dados constantes. Portanto, é preferível que a maioria dos seus dados (e principalmente as cadeias literais) permaneçam imutáveis . Leia mais sobre o paradigma de programação funcional .
Nos velhos Fortran77 dias na IBM / 7094, um erro poderia até mesmo mudar uma constante: se você CALL FOO(1)
e se FOO
aconteceu para modificar seu argumento passado por referência a 2, a implementação pode ter alterado outras ocorrências de 1 para 2, e que foi um realmente bug impertinente, bastante difícil de encontrar.