¿Cuál es el tipo de literales de cadena en C y C ++?

¿Cuál es el tipo de cadena literal en C? ¿Es char * o const char * o const char * const ?

¿Qué hay de C ++?

En C, el tipo de cadena literal es un char[] – no es const según el tipo, pero es un comportamiento indefinido modificar los contenidos. Además, dos literales de cadena diferentes que tienen el mismo contenido (o suficiente del mismo contenido) pueden o no compartir los mismos elementos de la matriz.

Del estándar C99 6.4.5 / 5 “literales de cuerda – Semántica”:

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 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; para literales de cadenas anchas, los elementos de la matriz tienen el tipo wchar_t , y se inicializan con la secuencia de caracteres anchos …

No se especifica si estas matrices son distintas siempre que sus elementos tengan los valores adecuados. Si el progtwig intenta modificar dicha matriz, el comportamiento no está definido.

En C ++, “Un literal de cadena ordinaria tiene el tipo ‘array of n const char ‘” (desde 2.13.4 / 1 “Literales de cadena”). Pero hay un caso especial en el estándar C ++ que hace que el puntero a los literales de cadena se convierta fácilmente en punteros no const calificados (4.2 / 2 “conversión de matriz a puntero”):

Un literal de cadena (2.13.4) que no es un literal de cadena ancha se puede convertir a un valor r de tipo “puntero a char”; un literal de cadena ancho se puede convertir a un valor r de tipo “puntero a wchar_t”.

Como nota al margen – porque las matrices en C / C ++ se convierten tan fácilmente en punteros, un literal de cadena se puede usar a menudo en un contexto de puntero, como cualquier matriz en C / C ++.


Editorialización adicional: lo que sigue es en su mayor parte especulación por mi parte sobre la lógica de las elecciones que hicieron los estándares C y C ++ con respecto a los tipos de cadenas literales. Así que tómalo con un grano de sal (pero por favor comenta si tienes correcciones o detalles adicionales):

Creo que el estándar C optó por hacer tipos literales sin const porque había (y hay) tanto código que espera poder usar punteros char no const calificados que apuntan a literales. Cuando se agregó el calificador const (que si no me equivoco se hizo alrededor del tiempo de estandarización ANSI, pero mucho después de que K & R C hubiera acumulado una tonelada de código existente) si hacían punteros a literales de cadena que solo se podían asignar Para char const* sin yeso, casi todos los progtwigs en existencia habrían requerido cambios. No es una buena forma de obtener un estándar aceptado …

Creo que el cambio a C ++ de que los literales de cadena están const calificados se hizo principalmente para permitir que una cadena literal coincida más apropiadamente con una sobrecarga que toma un argumento ” char const* “. Creo que también hubo un deseo de cerrar un orificio percibido en el sistema de tipos, pero el agujero se abrió en gran parte por el caso especial en las conversiones de matriz a puntero.

El anexo D de la norma indica que la “conversión implícita de const a no const calificación para literales de cadena (4.2) está en desuso”, pero creo que tanto código aún se romperá que pasará mucho tiempo antes de que los implementadores del comstackdor o el el comité de normas está dispuesto a desconectarse realmente (a menos que se pueda idear alguna otra técnica inteligente, pero luego el agujero volvería, ¿no?).

El literal de cadena de CA tiene el tipo char [n] donde n es igual a la cantidad de caracteres + 1 para tener en cuenta el cero implícito al final de la cadena.

La matriz se asignará estáticamente; no es const , pero modificarlo es un comportamiento indefinido.

Si tuviera el tipo de puntero char * o tipo incompleto char [] , sizeof no podría funcionar como se esperaba.

Convertir los literales de cadenas en const es un modismo de C ++ y no parte de ningún estándar de C.

Solían ser de tipo char[] . Ahora son de tipo const char[] .

Por diversas razones históricas, los literales de cadena siempre eran de tipo char[] en C.

Desde el principio (en C90), se afirmó que modificar un literal de cadena invoca un comportamiento indefinido.

Sin embargo, no prohibieron tales modificaciones ni hicieron que los literales de cadena const char[] tuvieran más sentido. Esto fue por razones de compatibilidad hacia atrás con el código anterior. Algunos sistemas operativos antiguos (sobre todo el DOS) no protestaron si modificaban los literales de cadena, por lo que había mucho de ese código.

C todavía tiene este defecto hoy, incluso en el estándar C más reciente.

C ++ heredó el mismo defecto de C, pero en los estándares posteriores de C ++, finalmente hicieron const literales de cadena const (marcados obsoletos en C ++ 03, finalmente corregidos en C ++ 11).