Storicamente (forse riscrivendone parti), era il contrario. Nei primissimi computer dei primi anni '70 (forse PDP-11 ) che eseguivano un prototipo C embrionale (forse BCPL ) non esistevano MMU e nessuna protezione della memoria (che esistevano sulla maggior parte dei mainframe IBM / 360 più vecchi ). Quindi ogni byte di memoria (compresi quelli che gestiscono stringhe letterali o codice macchina) potrebbe essere sovrascritto da un programma errato (immagina un programma cambiandone alcuni %
in /
in un printf (3) stringa di formato). Quindi, stringhe e costanti letterali erano scrivibili.
Da adolescente, nel 1975, ho codificato nel museo del Palais de la Découverte a Parigi su vecchi computer degli anni '60 senza protezione della memoria: IBM / 1620 aveva solo una memoria centrale, che era possibile inizializzare tramite la tastiera, quindi è stato necessario digitare diverse dozzine di cifre per leggere il programma iniziale su nastri punzonati; CAB / 500 aveva una memoria a tamburo magnetico; potresti disabilitare la scrittura di alcune tracce tramite interruttori meccanici vicino al tamburo.
Successivamente, i computer ottennero una qualche forma di unità di gestione della memoria (MMU) con una certa protezione della memoria. C'era un dispositivo che proibiva alla CPU di sovrascrivere un qualche tipo di memoria. Quindi alcuni segmenti di memoria, in particolare il segmento di codice (noto anche come .text
segmento), sono diventati di sola lettura (ad eccezione del sistema operativo che li ha caricati dal disco). Era naturale per il compilatore e il linker inserire le stringhe letterali in quel segmento di codice e le stringhe letterali diventavano di sola lettura. Quando il tuo programma ha cercato di sovrascriverli, è stato un comportamento indefinito . E avere un segmento di codice di sola lettura nella memoria virtuale offre un vantaggio significativo: diversi processi che eseguono lo stesso programma condividono la stessa RAM ( memoria fisicapagine) per quel segmento di codice (vedi MAP_SHARED
flag per mmap (2) su Linux).
Oggi, i microcontrollori economici hanno un po ' di memoria di sola lettura (ad esempio il loro Flash o ROM) e mantengono lì il loro codice (e le stringhe letterali e altre costanti). E i microprocessori reali (come quello sul tablet, laptop o desktop) hanno una sofisticata unità di gestione della memoria e un meccanismo di cache utilizzato per il paging e la memoria virtuale . Quindi il segmento di codice del programma eseguibile (ad es. In ELF ) è mappato in memoria come segmento di sola lettura, condivisibile ed eseguibile (da mmap (2) o esegui (2) per ottenere un segmento di codice scrivibile se lo desideri davvero) . Scrivere o abusare è generalmente un errore di segmentazione su Linux; BTW potresti dare direttive a ld.
Quindi lo standard C è barocco: legalmente (solo per ragioni storiche), le stringhe letterali non sono const char[]
array, ma solo char[]
array a cui è vietato sovrascrivere.
A proposito, poche lingue attuali consentono di sovrascrivere i letterali di stringa (anche Ocaml che storicamente - e malamente - aveva stringhe letterali scrivibili ha cambiato quel comportamento recentemente in 4.02, e ora ha stringhe di sola lettura).
Gli attuali compilatori C sono in grado di ottimizzare, avere "ions"
e"expressions"
condividere i loro ultimi 5 byte (incluso il byte null terminante).
Prova a compilare il codice C in un file foo.c
con gcc -O -fverbose-asm -S foo.c
e guardare all'interno del file assembler generato foo.s
da GCC
Alla fine, la semantica di C è abbastanza complessa (leggi di più su CompCert e Frama-C che stanno cercando di catturarlo) e l'aggiunta di stringhe letterali costanti scrivibili lo renderebbe ancora più arcano rendendo i programmi più deboli e persino meno sicuri (e con meno comportamento definito), quindi è molto improbabile che i futuri standard C accettino stringhe letterali scrivibili. Forse al contrario li avrebbero fatticonst char[]
array come dovrebbero essere moralmente.
Si noti inoltre che, per molte ragioni, i dati mutabili sono più difficili da gestire da parte del computer (coerenza della cache), codificare, comprendere dallo sviluppatore, che dati costanti. Quindi è preferibile che la maggior parte dei tuoi dati (e in particolare le stringhe letterali) rimangano immutabili . Ulteriori informazioni sul paradigma di programmazione funzionale .
Ai vecchi tempi di Fortran77 su IBM / 7094, un bug poteva persino cambiare una costante: se tu CALL FOO(1)
e se avessi FOO
modificato il suo argomento passato con riferimento a 2, l'implementazione avrebbe potuto cambiare altre occorrenze da 1 a 2, e quello era davvero bug cattivo, abbastanza difficile da trovare.