c++ - Cadena Dirección literal en las unidades de traducción
string string-literals (2)
Esta pregunta ya tiene una respuesta aquí:
Me gustaría preguntar si es portátil confiar en la dirección literal de cadena en las unidades de traducción. Es decir:
Un archivo dado
foo.c
tiene una referencia a un literal de cadena
"I''m a literal!"
, ¿es correcto y portátil confiar en que en otro archivo dado,
bar.c
, por ejemplo, que el
mismo literal de cadena
"I''m a literal!"
tendrá la
misma dirección de memoria
?
Teniendo en cuenta que cada archivo se traducirá a un archivo
.o
individual.
Para una mejor ilustración, sigue un código de ejemplo:
# File foo.c
/* ... */
const char * x = "I''m a literal!"
# File bar.c
/* ... */
const char * y = "I''m a literal!"
# File test.c
/* ... */
extern const char * x;
extern const char * y;
assert (x == y); //Is this assertion going to fail?
Y un ejemplo de líneas de comando gcc:
gcc -c -o foo.o -Wall foo.c
gcc -c -o bar.o -Wall bar.c
gcc -c -o test.o -Wall test.c
gcc -o test foo.o bar.o test.o
¿Qué pasa en la misma unidad de traducción? ¿Sería esto confiable si los literales de cadena están en la misma unidad de traducción?
No puede confiar en
literales de cadena
idénticos que tengan la misma ubicación de memoria, es una decisión de implementación.
El
borrador del estándar C99
nos dice que no se especifica si el mismo literal de cadena es distinto, de la sección
6.4.5
cadena
:
No se especifica si estas matrices son distintas siempre que sus elementos tengan los valores apropiados. Si el programa intenta modificar dicha matriz, el comportamiento es indefinido.
Para C ++ esto cubierto en el borrador de la sección estándar
2.14.5
cadena
que dice:
Si todos los literales de cadena son distintos (es decir, si están almacenados en objetos no superpuestos) se define la implementación. El efecto de intentar modificar un literal de cadena no está definido.
El compilador puede agrupar literales de cadena, pero tendría que comprender cómo funciona de compilador a compilador, por lo que esto no sería portátil y podría cambiar. Visual Studio incluye una opción para la agrupación literal de cadenas
En algunos casos, se pueden agrupar literales de cadena idénticos para ahorrar espacio en el archivo ejecutable. En la agrupación de literal de cadena, el compilador hace que todas las referencias a un literal de cadena particular apunten a la misma ubicación en la memoria, en lugar de tener cada punto de referencia a una instancia separada del literal de cadena. Para habilitar la agrupación de cadenas, use la opción del compilador / GF.
Tenga en cuenta que sí califica en algunos casos .
gcc
admite la agrupación y las unidades de compilación y puede activarlo mediante
-fmerge-constants
:
Intente fusionar constantes idénticas (constantes de cadena y constantes de punto flotante) en las unidades de compilación.
Esta opción es la predeterminada para la compilación optimizada si el ensamblador y el vinculador lo admiten. Use -fno-merge-constants para inhibir este comportamiento.
tenga en cuenta, el uso de intento y si ... apoyarlo .
En cuanto a una justificación, al menos para C, para no requerir que se agrupen los literales de cadena , podemos ver en esta discusión comp.std.c archivada sobre literales de cadena que la justificación se debió a la amplia variedad de implementación en ese momento:
El CCG podría haber servido como ejemplo pero no como motivación. En parte, el deseo de tener literales de cadena en datos ROMmable era admitir, er, ROMming. Recuerdo vagamente haber usado un par de implementaciones de C (antes de que se tomara la decisión X3J11) donde los literales de cadena se agrupaban automáticamente o se almacenaban en una sección de programa de datos constante. Dada la variedad existente de práctica y la disponibilidad de una solución fácil cuando se deseaban las propiedades originales de UNIX, parecía mejor no tratar de garantizar la unicidad y la capacidad de escritura de los literales de cadena.
No , no puedes esperar la misma dirección. Si sucede, sucede. Pero no hay nada que lo imponga.
§ 2.14.5 / p12
Si todos los literales de cadena son distintos (es decir, si están almacenados en objetos no superpuestos) se define la implementación. El efecto de intentar modificar un literal de cadena no está definido.
El compilador puede hacer lo que le plazca. Se pueden almacenar en diferentes direcciones si están en diferentes unidades de traducción o incluso si están en la misma unidad de traducción, independientemente del hecho de que son memorias de solo lectura.
En MSVC, por ejemplo, las direcciones son totalmente diferentes en ambos casos, pero de nuevo: nada impide que el compilador combine los valores de los punteros (ni siquiera donde , en la medida en que la restricción de la sección de solo lectura es obligatoria).