programming how from example curso compiler code caracteristicas c++ c

c++ - how - extern c



const char*const versus const char*? (12)

Estoy ejecutando algunos programas de ejemplo para familiarizarme con C ++ y me he encontrado con la siguiente pregunta. Primero, aquí está el código de ejemplo:

void print_string(const char * the_string) { cout << the_string << endl; } int main () { print_string("What''s up?"); }

En el código anterior, el parámetro para print_string podría haber sido const char * const the_string . ¿Cuál sería más correcto para esto?

Entiendo que la diferencia es que uno es un puntero a un carácter constante, mientras que el otro es un puntero constante a un carácter constante. Pero, ¿por qué funcionan ambos? ¿Cuándo sería relevante?


  1. Puntero mutable a un carácter mutable

    char *p;

  2. Puntero mutable a un carácter constante

    const char *p;

  3. Puntero constante a un carácter mutable

    char * const p;

  4. Puntero constante a un carácter constante

    const char * const p;


Casi todas las otras respuestas son correctas, pero se olvidan de un aspecto de esto: cuando se usa el const adicional en un parámetro en una declaración de función, el compilador esencialmente lo ignorará. Por un momento, ignoremos la complejidad de que su ejemplo sea un puntero y simplemente usemos un int .

void foo(const int x);

declara la misma función que

void foo(int x);

Solo en la definición de la función se encuentra el significado adicional:

void foo(const int x) { // do something with x here, but you cannot change it }

Esta definición es compatible con cualquiera de las declaraciones anteriores. A la persona que llama no le importa que x sea const es un detalle de implementación que no es relevante en el sitio de llamadas.

Si tiene un puntero const para const data, se aplican las mismas reglas:

// these declarations are equivalent void print_string(const char * const the_string); void print_string(const char * the_string); // In this definition, you cannot change the value of the pointer within the // body of the function. It''s essentially a const local variable. void print_string(const char * const the_string) { cout << the_string << endl; the_string = nullptr; // COMPILER ERROR HERE } // In this definition, you can change the value of the pointer (but you // still can''t change the data it''s pointed to). And even if you change // the_string, that has no effect outside this function. void print_string(const char * the_string) { cout << the_string << endl; the_string = nullptr; // OK, but not observable outside this func }

Pocos programadores de C ++ se molestan en establecer parámetros, incluso cuando podrían ser, independientemente de si esos parámetros son punteros.


Creo que es muy poco relevante, ya que su función no se llama con argumentos como & * the_string o ** the_string. El puntero en sí es un argumento de tipo valor, por lo que incluso si lo modifica, no va a cambiar la copia que se utilizó para llamar a su función. La versión que muestra garantiza que la cadena no cambiará, y creo que eso es suficiente en este caso.


En este último caso, está garantizando que no modificará tanto el puntero como el carácter en el primero; solo garantiza que el contenido no cambiará, pero puede mover el puntero alrededor del puntero.


Esto último le impide modificar the_string dentro de print_string . En realidad sería apropiado aquí, pero tal vez la verborrea posponga al desarrollador.

char* the_string : Puedo cambiar el char al que apunta the_string , y puedo modificar el char al que apunta.

const char* the_string : puedo cambiar el char al que apunta the_string , pero no puedo modificar el char al que apunta.

char* const the_string : no puedo cambiar el char al que apunta the_string , pero puedo modificar el char al que apunta.

const char* const the_string : no puedo cambiar el char al que apunta the_string , ni puedo modificar el char al que apunta.


La diferencia entre los dos es que char * puede apuntar a cualquier puntero arbitrario. Const char *, por el contrario, apunta a las constantes definidas en la sección de DATOS del ejecutable. Y, como tal, no puede modificar los valores de los caracteres de una cadena const char *.


La diferencia es que sin la const adicional el programador podría cambiar, dentro del método, hacia donde señala el puntero; por ejemplo:

void print_string(const char * the_string) { cout << the_string << endl; //.... the_string = another_string(); //.... }

Eso sería en cambio ilegal si la firma fuera void print_string(const char * const the_string)

Muchos programadores se sienten demasiado detallados (en la mayoría de los escenarios) como la palabra clave const y la omiten, aunque sería semánticamente correcta.


Muchas personas sugieren leer el especificador de tipos de derecha a izquierda.

const char * // Pointer to a `char` that is constant, it can''t be changed. const char * const // A const pointer to const data.

En ambas formas, el puntero apunta a datos constantes o de solo lectura.

En la segunda forma, el puntero no se puede cambiar; el puntero siempre apunta al mismo lugar.


No hay ninguna razón por la cual ninguno de los dos funcione. Todo print_string() hace es imprimir el valor. No intenta modificarlo.

Es una buena idea hacer una función que no modifique argumentos de marca como const. La ventaja es que las variables que no pueden cambiarse (o que no desea cambiar) se pueden pasar a estas funciones sin error.

En cuanto a la sintaxis exacta, desea indicar qué tipo de argumentos son "seguros" para pasar a la función.


const char * const significa puntero, así como los datos apuntados por el puntero, ¡ ambos son const!

const char * significa solo los datos apuntados por el puntero, es const. el puntero en sí mismo, sin embargo, no es const.

Ejemplo.

const char *p = "Nawaz"; p[2] = ''S''; //error, changing the const data! p="Sarfaraz"; //okay, changing the non-const pointer. const char * const p = "Nawaz"; p[2] = ''S''; //error, changing the const data! p="Sarfaraz"; //error, changing the const pointer.


const char * significa que no puede usar el puntero para cambiar lo que se apunta. Sin embargo, puedes cambiar el puntero para apuntar a otra cosa.

Considerar:

const char * promptTextWithDefault(const char * text) { if ((text == NULL) || (*text == ''/0'')) text = "C>"; return text; }

El parámetro es un puntero no const para const char, por lo que se puede cambiar a otro valor const char * (como una cadena constante). Sin embargo, si escribimos erróneamente *text = ''/0'' , obtendríamos un error de compilación.

Podría decirse que, si no pretende cambiar a lo que apunta el parámetro, podría hacer que el parámetro const char * const text , pero no es común hacerlo. Normalmente permitimos que las funciones cambien los valores pasados ​​a los parámetros (porque pasamos los parámetros por valor, cualquier cambio no afecta a la persona que llama).

Por cierto: es una buena práctica evitar char const * porque a menudo se lee mal - significa lo mismo que const char * , pero demasiadas personas lo leen como " char * const .


(Sé que esto es viejo, pero quería compartirlo de todos modos).

Solo quería dar más detalles sobre la respuesta de Thomas Matthews. Las declaraciones de la derecha de la regla de tipo C dicen más o menos: al leer una declaración de tipo C, comience por el identificador, vaya a la derecha cuando pueda y, cuando no, vaya a la izquierda.

Esto se explica mejor con un par de ejemplos:

Ejemplo 1

  • Comience por el identificador, no podemos ir a la derecha, así que vamos a la izquierda

    const char* const foo ^^^^^

    foo es una constante ...

  • Continuar izquierda

    const char* const foo ^

    foo es un puntero constante para ...

  • Continuar izquierda

    const char* const foo ^^^^

    foo es un puntero constante para char ...

  • Continuar izquierda

    const char* const foo ^^^^^

    foo es un puntero constante a la constante de char (¡Completa!)

Ejemplo 2

  • Comience por el identificador, no podemos ir a la derecha, así que vamos a la izquierda

    char* const foo ^^^^^

    foo es una constante ...

  • Continuar izquierda

    char* const foo ^

    foo es un puntero constante para ...

  • Continuar izquierda

    char* const foo ^^^^

    foo es un puntero constante a char (¡Completa!)

Ejemplo 1337

  • Comience en el identificador, pero ahora podemos ir a la derecha!

    const char* const* (*foo[8])() ^^^

    foo es una matriz de 8 ...

  • Toca el paréntesis para que no pueda continuar, ve a la izquierda

    const char* const* (*foo[8])() ^

    foo es una matriz de 8 punteros a ...

  • Terminado entre paréntesis, ahora puede ir a la derecha

    const char* const* (*foo[8])() ^^

    foo es una matriz de 8 punteros a la función que devuelve ...

  • Nada más a la derecha, gire a la izquierda

    const char* const* (*foo[8])() ^

    foo es una matriz de 8 punteros a la función que devuelve un puntero a un ...

  • Continuar izquierda

    const char* const* (*foo[8])() ^^^^^

    foo es una matriz de 8 punteros a funciones que devuelve un puntero a una constante ...

  • Continuar izquierda

    const char* const* (*foo[8])() ^

    foo es una matriz de 8 punteros a funciones que devuelve un puntero a un puntero constante a un ...

  • Continuar izquierda

    const char* const* (*foo[8])() ^^^^

    foo es una matriz de 8 punteros a funciones que devuelve un puntero a un puntero constante a un carácter ...

  • Continuar izquierda

    const char* const* (*foo[8])() ^^^^^

    foo es una matriz de 8 punteros a funciones que devuelve un puntero a un puntero constante a una constante char (¡Completa!)

Explicación adicional: http://www.unixwiz.net/techtips/reading-cdecl.html