Puedo ver dos 'some'
literales en el código ensamblador generado por MSVC, pero solo uno con clang y gcc. Esto conduce a resultados totalmente diferentes de ejecución de código.
static const char *A = "some";
static const char *B = "some";
void f() {
if (A == B) {
throw "Hello, string merging!";
}
}
¿Alguien puede explicar la diferencia y las similitudes entre esos resultados de compilación? ¿Por qué clang / gcc optimiza algo incluso cuando no se solicitan optimizaciones? ¿Es este algún tipo de comportamiento indefinido?
También noto que si cambio las declaraciones a las que se muestran a continuación, clang / gcc / msvc no deja ninguna "some"
en el código ensamblador. ¿Por qué el comportamiento es diferente?
static const char A[] = "some";
static const char B[] = "some";
c++
language-lawyer
string-literals
string-interning
Eugene Kosov
fuente
fuente
Respuestas:
Este no es un comportamiento indefinido, sino un comportamiento no especificado. Para cadenas literales ,
Eso significa que el resultado de
A == B
podría sertrue
ofalse
, del cual no deberías depender.Desde el estándar, [lex.string] / 16 :
fuente
Las otras respuestas explicaron por qué no puede esperar que las direcciones de puntero sean diferentes. Sin embargo, puede reescribir esto fácilmente de una manera que garantice eso
A
yB
no se compare igual:La diferencia es que
A
yB
ahora son matrices de personajes. Esto significa que no son punteros y sus direcciones tienen que ser distintas, como tendrían que ser las de dos variables enteras. C ++ confunde esto porque hace que los punteros y las matrices parezcan intercambiables (operator*
yoperator[]
parecen comportarse de la misma manera), pero son realmente diferentes. Por ejemplo, algo comoconst char *A = "foo"; A++;
es perfectamente legal, peroconst char A[] = "bar"; A++;
no lo es.Una forma de pensar en la diferencia es que
char A[] = "..."
dice "dame un bloque de memoria y rellénalo con los caracteres...
seguidos de\0
", mientras quechar *A= "..."
dice "dame una dirección en la que pueda encontrar los caracteres...
seguidos de\0
".fuente
*p
yp[0]
no sólo "parecen comportarse igual", sino que por definición son idénticos (siempre quep+0 == p
sea una relación de identidad porque0
es el elemento neutral en la suma de puntero-entero). Después de todo,p[i]
se define como*(p+i)
. Sin embargo, la respuesta tiene un buen punto.typeof(*p)
ytypeof(p[0])
son ambos,char
por lo que realmente no queda mucho que pueda ser diferente. Estoy de acuerdo en que "parece que se comportan igual" no es la mejor redacción, porque la semántica es muy diferente. Tu entrada me recordó la mejor forma de elementos de acceso de matrices de C ++:0[p]
,1[p]
,2[p]
etc. Así es como lo hacen los profesionales, al menos cuando quieren confundir a las personas que nacieron después de que el lenguaje de programación C.Si un compilador elige usar la misma ubicación de cadena para la implementación
A
yB
depende de ella. Formalmente, puede decir que el comportamiento de su código no está especificado .Ambas opciones implementan correctamente el estándar C ++.
fuente
Es una optimización para ahorrar espacio, a menudo llamada "agrupación de cadenas". Aquí están los documentos para MSVC:
https://msdn.microsoft.com/en-us/library/s0s0asdt.aspx
Por lo tanto, si agrega / GF a la línea de comando, debería ver el mismo comportamiento con MSVC.
Por cierto, probablemente no debería comparar cadenas a través de punteros como ese, cualquier herramienta de análisis estático decente marcará ese código como defectuoso. Debe comparar lo que apuntan, no los valores reales del puntero.
fuente