2012-04-22 47 views
13

Sé que, por ejemplo, "hello" es del tipo const char*. Así que mis preguntas son:¿Por qué es posible asignar un const char * a un char *?

  1. ¿Cómo podemos asignar una cadena literal como "hello" a un no const char* así:

    char* s = "hello"; // "hello" is type of const char* and s is char* 
            // and we know that conversion from const char* to 
            // char* is invalid 
    
  2. es una cadena literal como "hello", que se llevará a la memoria en todo mi programa, o es solo una variable temporal que se destruirá cuando termine el enunciado

+2

Esto solo se permite para la compatibilidad con C. Generalmente en C++ se considera obsoleto y los buenos compiladores dan una advertencia. – iammilind

Respuesta

22

De hecho, "hello" es de tipo char const[6].

Pero la esencia de la pregunta sigue siendo correcta: ¿por qué C++ nos permite asignar una ubicación de memoria de solo lectura a un tipo que no sea const?

La única razón para esto es la compatibilidad con versiones anteriores del código C antiguo, que no sabía const. Si C++ hubiera sido estricto aquí habría roto un montón de código existente.

Dicho esto, la mayoría de los compiladores se pueden configurar a advierten sobre el código como obsoleto, o incluso lo hacen de forma predeterminada. Además, C++ 11 no permite esto por completo, pero los compiladores pueden no aplicarlo todavía.


Para aficionados Standerdese:
[Ref 1]C++ 03 estándar: § 4.2/2

Una cadena literal (2.13.4) que no es una amplia el literal de cadena 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". En cualquier caso, el resultado es un puntero al primer elemento de la matriz. Esta conversión se considera solo cuando hay un tipo de destino de puntero apropiado explícito, y no cuando hay una necesidad general de convertir de un valor l a un valor r. [Nota: esta conversión está en desuso. Ver el Anexo D.] Con el propósito de clasificar en resolución de sobrecarga (13.3.3.1.1), esta conversión se considera una conversión de matriz a punta seguido por una conversión de calificación (4.4). [Ejemplo: "abc" se convierte en "puntero a const char" como una conversión de matriz a puntero, y luego a "puntero a char" como una conversión de calificación. ]

C++ 11 simplemente elimina la cita anterior que implica que es código ilegal en C++ 11.

[Ref 2]C99 estándar 6.4.5/5 "literales de cadena - Semántica":

En fase de traducción 7, un byte o código de valor cero se adjunta a cada carácter multibyte secuencia que resulta de una cadena literal o literales. 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 cadena ancha, los elementos de 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 programa intenta modificar dicha matriz, el comportamiento no está definido.

+1

Agregó las citas relevantes de la Norma. Espero que no te importe eso. –

+0

MSVC en modo de depuración le impedirá escribir en un literal de cadena en tiempo de ejecución, GCC en tiempo de compilación (si es posible). Sin embargo, hay una opción, creo que es -wwrite-strings o such that enciende el modo de compatibilidad y pone literales de cadena en la memoria R/W –

+2

@Als Ha tomado un poco de simplicidad y lo ha hecho feo. ;-) Pero gracias.En realidad, quería agregar eso también, pero no puedo encontrar los pasajes relevantes en mi borrador de C++ 11 en absoluto. 2.14.3 define el tipo, y el anexo especifica la invalidez de la conversión, pero nada muestra que esto fue obsoleto, pero es válido en C++ 03. –

1

sólo tiene que utilizar un string:

std::string s("hello"); 

Esa sería la forma de C++. Si realmente debe usar char, deberá crear una matriz y copiar el contenido sobre ella.

2

cadena literal como "hola" tomará memoria en todo mi programa, todo es solo una variable temporal que se destruirá cuando finalice la instrucción.

Se almacena en los datos del programa, por lo que se puede esperar durante la vida útil del programa. Puede devolver punteros y referencias a estos datos del alcance actual.

La única razón por la cual const char* se está convirtiendo en char* es concomitante con c, como las llamadas al sistema winapi. Y este elenco se convierte en inexplicit a diferencia de cualquier otro casting const.

+0

por lo que const char * es el único tipo que el compilador puede convertir a char * de manera no explícita. – AlexDan

+0

AlexDan, 'const char *' es el único tipo que se puede convertir a su forma no constante (por ejemplo, 'const int *' no se puede convertir a 'int *' de manera no explícita). Pero puedes ajustar el compilador para generar un waring. –

+2

también, * cast * es un verbo irregular, 3 formas: * cast-cast-cast * –

-3

En su ejemplo, no está asignando, sino construyendo. std :: string, por ejemplo, tiene un constructor std::string(const char *) (en realidad es más complicado, pero no importa). Y, de manera similar, char * (si era un tipo en lugar de un puntero a un tipo) podría tener un constructor const char *, que está copiando la memoria.

Realmente no sé cómo funciona realmente el compilador aquí, pero creo que podría ser similar a lo que he descrito anteriormente: una copia de "Hello" se construye en pila y s se inicializa con la dirección de esta copia.

+2

Esto simplemente no es correcto. No se realiza ninguna copia, y la modificación de la cadena a través del puntero es UB. –

+0

¡No hay copia de "Hola" en la pila! Es un literal de cadena que se creará en algún [segmento de datos] global (https://secure.wikimedia.org/wikipedia/en/wiki/Data_segment) (pero este es un detalle específico de la implementación). – Praetorian

+0

@KonradRudolph, nunca dije que fuera correcto. Estoy triste, que podría ser así. Gracias por los enlaces de todos modos. – Steed

1

La respuesta a su segunda pregunta es que la variable s se almacena en la memoria RAM como tipo puntero-a-char. Si es global o estático, se asigna en el montón y permanece allí durante toda la vida del programa en ejecución. Si se trata de una variable local ("auto"), se asigna en la pila y permanece allí hasta que la función actual regrese. En cualquier caso, ocupa la cantidad de memoria requerida para contener un puntero.

La cadena "Hello" es una constante, y se almacena como parte del programa en sí, junto con todas las demás constantes e inicializadores. Si creó su programa para ejecutar en un dispositivo, la cadena se almacenará en la ROM.

Tenga en cuenta que, como la cadena es constante y s es un puntero, no es necesario copiar. El puntero s simplemente apunta a donde se almacena la cadena.

Cuestiones relacionadas