Históricamente (tal vez reescribiendo partes de él), fue todo lo contrario. En las primeras computadoras de principios de la década de 1970 (quizás PDP-11 ) que ejecutaban un C embrionario prototípico (quizás BCPL ) no había MMU ni protección de memoria (que existía en la mayoría de los mainframes IBM / 360 más antiguos ). Por lo tanto, cada byte de memoria (incluidos los que manejan cadenas literales o código de máquina) podría ser sobrescrito por un programa erróneo (imagine un programa cambiando algunos %
a /
una cadena de formato printf (3) ). Por lo tanto, las cadenas literales y las constantes se podían escribir.
Cuando era adolescente en 1975, codifiqué en el museo Palais de la Découverte en París en computadoras antiguas de la década de 1960 sin protección de memoria: IBM / 1620 tenía solo una memoria central, que se podía inicializar a través del teclado, por lo que tenía que escribir varias docenas de dígitos para leer el programa inicial en cintas perforadas; CAB / 500 tenía una memoria de tambor magnético; puede deshabilitar la escritura de algunas pistas a través de interruptores mecánicos cerca del tambor.
Más tarde, las computadoras obtuvieron algún tipo de unidad de administración de memoria (MMU) con cierta protección de memoria. Había un dispositivo que prohibía a la CPU sobrescribir algún tipo de memoria. Entonces, algunos segmentos de memoria, en particular el segmento de código (también conocido como .text
segmento) se convirtió en solo lectura (excepto por el sistema operativo que los cargó desde el disco). Era natural que el compilador y el enlazador pusieran las cadenas literales en ese segmento de código, y las cadenas literales se volvieron de solo lectura. Cuando su programa intentó sobrescribirlos, fue malo, un comportamiento indefinido . Y tener un segmento de código de solo lectura en la memoria virtual ofrece una ventaja significativa: varios procesos que ejecutan el mismo programa comparten la misma RAM ( memoria físicapáginas) para ese segmento de código (vea el MAP_SHARED
indicador para mmap (2) en Linux).
Hoy en día, los microcontroladores baratos tienen algo de memoria de solo lectura (por ejemplo, su Flash o ROM), y mantienen allí su código (y las cadenas literales y otras constantes). Y los microprocesadores reales (como el de su tableta, computadora portátil o computadora de escritorio) tienen una unidad de administración de memoria sofisticada y maquinaria de caché utilizada para memoria virtual y paginación . Por lo tanto, el segmento de código del programa ejecutable (por ejemplo, en ELF ) está mapeado en memoria como un segmento de solo lectura, compartible y ejecutable (por mmap (2) o execve (2) en Linux; por cierto, podría dar instrucciones a ldpara obtener un segmento de código grabable si realmente lo desea). Escribirlo o abusarlo generalmente es una falla de segmentación .
Por lo tanto, el estándar C es barroco: legalmente (solo por razones históricas), las cadenas literales no son const char[]
matrices, sino solo char[]
matrices que tienen prohibido sobrescribirse.
Por cierto, pocos idiomas actuales permiten que se sobrescriban los literales de cadena (incluso Ocaml, que históricamente -y mal- tenía cadenas literales de escritura ha cambiado ese comportamiento recientemente en 4.02, y ahora tiene cadenas de solo lectura).
Los compiladores actuales de C pueden optimizar y tener "ions"
y "expressions"
compartir sus últimos 5 bytes (incluido el byte nulo de terminación).
Tratar de compilar el código C en el archivo foo.c
con gcc -O -fverbose-asm -S foo.c
y mirada dentro del archivo de ensamblador generado foo.s
por GCC
Por último, la semántica de C es lo suficientemente compleja (lea más sobre CompCert y Frama-C, que están tratando de capturarlo) y agregar cadenas literales constantes y grabables lo haría aún más arcano mientras hace que los programas sean más débiles y menos seguros (y con menos comportamiento definido), por lo que es muy poco probable que los futuros estándares C acepten cadenas literales grabables. Quizás, por el contrario, los convertirían en const char[]
matrices como deberían ser moralmente.
Observe también que, por muchas razones, los datos mutables son más difíciles de manejar por la computadora (coherencia de caché), de codificar, de entender por el desarrollador, que los datos constantes. Por lo tanto, es preferible que la mayoría de sus datos (y especialmente las cadenas literales) permanezcan inmutables . Lea más sobre el paradigma de programación funcional .
En los viejos días de Fortran77 en IBM / 7094, un error incluso podía cambiar una constante: si usted CALL FOO(1)
y si FOO
modificara su argumento pasado por referencia a 2, la implementación podría haber cambiado otras ocurrencias de 1 a 2, y eso fue realmente bicho travieso, bastante difícil de encontrar.