2008-11-05 26 views
24

Siempre trato de evitar devolver literales de cadena, porque me temo que no están definidos fuera de la función. Pero no estoy seguro si este es el caso. Vamos a tomar, por ejemplo, esta función:Alcance de (cadena) literales


const char * 
return_a_string(void) 
{ 
    return "blah"; 
} 

¿Este código correcto? Funciona para mí, pero tal vez solo funciona para mi compilador (gcc). Entonces, la pregunta es, ¿los literales (de cadena) tienen un alcance o están presentes/definidos todo el tiempo?

Respuesta

35

Este código es correcto en todas las plataformas. La cadena se compila en el binario como un literal de cadena estática. Si está en Windows, por ejemplo, incluso puede abrir su .exe con el bloc de notas y buscar la cadena en sí.

Dado que es una cadena estática, el alcance literal no importa.

cadena puesta en común:

Una cosa a tener en cuenta es que, en algunos casos, los literales de cadena idénticos pueden ser "agrupados" para ahorrar espacio en el archivo ejecutable. En este caso, cada literal de cadena que sea el mismo podría tener la misma dirección de memoria. Sin embargo, nunca debes asumir que será o no será el caso.

En la mayoría de los compiladores puede configurar si se usa o no la agrupación de cadenas estáticas para mezclar literales.

tamaño máximo de los literales de cadena:

Varios compiladores tienen un tamaño máximo para la cadena literal. Por ejemplo, con VC++ esto es aproximadamente 2.048 bytes.

Modificación de una cadena literal da un comportamiento indefinido:

Modificación de una cadena literal nunca debe hacerse. Tiene un comportamiento indefinido.

char * sz = "this is a test"; 
sz[0] = 'T'; //<--- undefined results 

literales de cadena Ancho:

Todo lo anterior se aplica igualmente a los literales de cadena de ancho.

Ejemplo: L "esto es una cadena literal ancha";

El C++ estados estándar: (sección lex.string)

1 Una cadena literal es una secuencia de caracteres (tal como se define en lex.ccon) rodeado por comillas dobles, opcionalmente comenzando con la letra L de , como en "..." o L "...". Un literal de cadena que no comienza en con L es un literal de cadena ordinario, también conocido como literal de cadena estrecho. Una cadena ordinaria literal tiene tipo "matriz de n const char" y la duración de almacenamiento estático (basic.stc), donde n es el tamaño de la cadena como se define a continuación, y se inicializa con los dados caracteres.Un literal de cadena que comienza con L, como L "asdf", es literal de cadena ancha. Una amplia cadena literal tiene tipo "array de n wchar_t const" y tiene una duración de almacenamiento estático, donde n es el tamaño de la cadena como se define a continuación, y se inicializa con los dados terísticas tros.

2 Si todos los literales de cadena son distintos (es decir, se almacenan en objetos que no se superponen) está definido por la implementación. El efecto de intentando modificar una cadena literal no está definido.

+0

Ya que menciona explícitamente los literales de cadena de ancho, hacen todos los literales se comportan de esa manera? Con cada me refiero a los literales compuestos c99. – quinmars

+0

no puedo pensar en cualquier otra literales que esto podría aplicarse a, pero podría haber otros.Otros literales tendrían sus propias reglas, pero en relación con su pregunta original, si devolvió, por ejemplo, un número entero, entonces sí, eso es seguro. –

+2

Lo que quise decir es que las construcciones C99 donde se puede crear una estructura o una matriz sobre la marcha como (int []) {1, 2, 3, 4}. Sé que esto no fue parte de mi pregunta inicial, pero como mencionaste literales de cadenas anchas, tengo curiosidad sobre los otros literales :). – quinmars

2

Sí, está bien. Viven en una tabla de cadenas global.

2

No, los literales de cadenas no tienen alcance, por lo que se garantiza que su código funcionará en todas las plataformas y compiladores. Se almacenan en la imagen binaria de tu programa, por lo que siempre puedes acceder a ellos. Sin embargo, tratar de escribirles (descartando el const) conducirá a un comportamiento indefinido.

0

En realidad, devuelve un puntero a la cadena terminada en cero almacenada en la sección de datos del ejecutable, un área cargada al cargar el programa. Solo evite tratar de cambiar los caracteres, podría dar resultados impredecibles ...

0

Es muy importante tomar nota de los resultados indefinidos que Brian mencionó. Como ha declarado que la función devuelve un tipo const char *, debería estar bien, pero en muchas plataformas los literales de cadena se colocan en un segmento de solo lectura en el ejecutable (generalmente el segmento de texto) y modificarlos causará una infracción de acceso. en la mayoría de las plataformas.

2

Esto es válido en C (o C++), como otros han explicado.

Lo único que puedo pensar en tener en cuenta es que si está usando dlls, entonces el puntero no seguirá siendo válido si el dll que contiene este código está descargado.

El estándar C (o C++) no comprende ni tiene en cuenta el código de carga y descarga en tiempo de ejecución, por lo que cualquier cosa que haga eso tendrá consecuencias definidas por la implementación: en este caso la consecuencia es que la cadena literal, se supone que tiene una duración de almacenamiento estático, aparece desde el punto de vista del código de llamada para no persistir durante toda la duración del programa.

7

Os pongo un ejemplo para que su confusión se convierte en algo claro

char *f() 
{ 
char a[]="SUMIT"; 
return a; 
} 

esto no funcionará.

pero

char *f() 
{ 
char *a="SUMIT"; 
return a; 
} 

esto funciona.

Motivo: "SUMIT" es un literal que tiene un alcance global. mientras que la matriz que es solo una secuencia de caracteres {'S', 'U', 'M', 'I', "T '' \ 0 '} tiene un alcance limitado y desaparece tan pronto como el programa regresó.

esperanza esto ayuda

Cuestiones relacionadas