c++ - resueltos - ¿Se puede asignar una cadena estática const a la pila?
imprimir cadena de caracteres en c (5)
const char * foo()
{
return "abcdef";
}
int main()
{
printf("%s", foo());
}
¿Puede un compilador conforme decidir asignar "abcdef"
en la pila? Es decir, ¿qué en el estándar obliga al compilador a asignarlo en la sección .data
?
¿Qué en el estándar obliga al compilador a asignarlo en la sección .data?
Nada. Pero ciertamente no puede estar en la pila, ya que los punteros a una cadena literal nunca deben invalidarse (ya que el literal tiene una duración de almacenamiento estático 1 ), y los valores de la pila se sobrescribirán por otros marcos en algún momento. Y los objetos con duración de almacenamiento estática generalmente se encuentran en una sección dedicada a eso, la sección .data
.
Bajo la regla de si-si, podría ponerlo en la pila si el comportamiento observable del programa no cambia; Sin embargo, es muy poco probable que suceda, ya que eso no beneficiaría el rendimiento del programa de ninguna manera (y aún no se han escrito los compiladores relevantes sin sentido).
1) [lex.string] / 8:
Los literales de cadena ordinarios y los literales de cadena UTF-8 también se conocen como literales de cadena estrecha. Un literal de cadena estrecha tiene el tipo "matriz de n
const char
", donde n es el tamaño de la cadena como se define a continuación, y tiene una duración de almacenamiento estático (3.7).
De la especificación de C ++ § 2.14.5 / 8 para literales de cadena;
Los literales de cadena ordinarios y los literales de cadena UTF-8 también se conocen como literales de cadena estrecha. Un literal de cadena estrecha tiene el tipo "matriz de n
const char
", donde n es el tamaño de la cadena como se define a continuación, y tiene una duración de almacenamiento estático (3.7).
También vale la pena mencionar que la duración del almacenamiento estático se aplica a todos los literales de cadena ; por lo tanto L""
, u""
, U""
etc; § 2.14.5 / 10-12.
A su vez, para la duración de almacenamiento estático § 3.7.1 / 1;
Todas las variables que no tienen una duración de almacenamiento dinámico, no tienen duración de almacenamiento de subprocesos y no son locales tienen duración de almacenamiento estático. El almacenamiento para estas entidades durará por la duración del programa (3.6.2, 3.6.3).
Por lo tanto, su cadena "abcdef"
existirá durante la duración del programa. El compilador puede elegir dónde almacenarlo (y esto puede ser una restricción del sistema), pero debe seguir siendo válido.
Para la especificación de lenguaje C (C11 borrador n1570), literales de cadena § 6.4.5 / 6;
En la fase de traducción 7, se agrega un byte o código de valor cero a cada secuencia de caracteres multibyte que resulta de una cadena literal o literal. La secuencia de caracteres multibyte se usa luego para inicializar una matriz de duración de almacenamiento estático y longitud suficiente para contener la secuencia. Para los literales de cadena de caracteres, los elementos de la matriz tienen tipo
char
, y se inicializan con los bytes individuales de la secuencia de caracteres multibyte.
Y la duración de almacenamiento estática § 6.2.4 / 3;
Un objeto cuyo identificador se declara sin el especificador de clase de almacenamiento
_Thread_local
, y con enlace externo o interno o con el especificador de clase de almacenamiento estático, tiene una duración de almacenamiento estático. Su duración es la ejecución completa del programa y su valor almacenado se inicializa solo una vez, antes del inicio del programa.
Se aplica el mismo razonamiento para la ubicación (lo más probable es que sea una restricción del sistema), pero debe seguir siendo válida durante la duración del programa.
Las respuestas anteriores ya han sido citadas del estándar, por lo que iré con el enfoque lógico.
Puede copiar esta cadena literal de la sección de datos RO en la pila cada vez que se llame a la función:
const char* foo()
{
const char str[] = "abcdef";
return str;
}
Pero esta función devuelve un puntero.
Y ciertamente no quiere que este puntero contenga una dirección en la pila.
Entonces no tiene sentido tener esa cadena literal asignada en la pila para empezar.
Remitiéndose a N1570 (C11 draft) 6.4.5/6
Literales 6.4.5/6
cadenas (énfasis mío en el futuro):
En la fase de traducción 7, se agrega un byte o código de valor cero a cada secuencia de caracteres multibyte que resulta de una cadena literal o literal. 78) La secuencia de caracteres multibyte se usa para inicializar una matriz de duración de almacenamiento estático y longitud suficiente para contener la secuencia. Para los literales de cadena de caracteres, los elementos de la matriz tienen tipo
char
, y se inicializan con los bytes individuales de la secuencia de caracteres multibyte.
Esto significa que los literales de cadena tienen una duración de toda la ejecución del programa, como se menciona en 6.2.4/3
almacenamiento de los objetos :
Un objeto cuyo identificador se declara sin el especificador de clase de almacenamiento
_Thread_local
, y con enlace externo o interno o con el especificador de clase de almacenamientostatic
, tiene una duración de almacenamiento estático . Su duración es la ejecución completa del programa y su valor almacenado se inicializa solo una vez, antes del inicio del programa .
Es poco probable que el compilador los coloque en la pila, debido a su naturaleza (pista: preservación entre las llamadas de las funciones).
Tenga en cuenta que C Standard no prohíbe explícitamente colocar literales de cadena en la pila. De hecho, ni siquiera define un término como pila ni sección de datos. Depende del compilador, elegir cualquier ubicación de datos que cumpla con el estándar.
Todo lo de duración estática debe permanecer asignado hasta que el programa finalice; sería posible que tales cosas se ubicaran en la pila, pero solo si se asignan antes de que se ejecute cualquier código de usuario . Tal diseño sería inusual, pero podría ser ventajoso, por ejemplo, en una arquitectura de plug-in en la que se desea tener varios subprocesos ejecutar un complemento de forma simultánea y hacer que cada instancia de hilo se comporte de manera completamente independiente. Si la arquitectura tuviera todas las instancias de un complemento que compartan los mismos datos estáticos, al menos desde el punto de vista de la arquitectura del complemento, los datos que no deberían compartirse no deberían ser estáticos. Si bien podría decirse que sería mejor tener cada instancia almacenando sus datos estáticos en un bloque de espacio solicitado desde el montón, eso requeriría que cada instancia liberara ese bloque de espacio cuando se completara. Tener cada instancia de complemento asignando todos sus datos en su pila (incluido un tamaño de char[]
adecuado char[]
que se subdividiría para satisfacer malloc()
o new
solicitudes) antes de ejecutar el código de usuario garantizaría que se elimine el hilo asociado con un instancia liberaría el almacenamiento asociado con él.