¿Por qué son válidos tanto "const T" como "T const" y cuál debería utilizar?
Para empezar, probablemente sepa que const
se puede utilizar para hacer que los datos de un objeto o un puntero no sean modificables, o ambos.
const Object* obj; // can't change data
Object* const obj; // can't change pointer
const Object* const obj; // can't change data or pointer
Sin embargo, también puedes utilizar la sintaxis:
Object const *obj; // same as const Object* obj;
Lo único que parece importar es en qué lado del asterisco pones la const
palabra clave. Personalmente, prefiero colocarlo const
a la izquierda del tipo para especificar que sus datos no se pueden modificar, ya que creo que se lee mejor en mi mentalidad de izquierda a derecha, pero ¿qué sintaxis apareció primero?
Más importante aún, ¿por qué existen dos formas correctas de especificar const
datos y en qué situación preferiría o necesitaría una sobre la otra, si corresponde?
Editar
Entonces parece que fue una decisión arbitraria cuando el estándar sobre cómo los compiladores deberían interpretar las cosas se redactó mucho antes de que yo naciera. Dado que const
se aplica a lo que está a la izquierda de la palabra clave (¿de forma predeterminada?), Supongo que pensaron que no había ningún daño en agregar "atajos" para aplicar palabras clave y escribir calificadores de otras maneras, al menos hasta el momento en que la declaración cambie por analizando un *
o &
...
Supongo que este también fue el caso en C.
¿Por qué hay dos formas correctas de especificar
const
datos y en qué situación preferiría o necesitaría una sobre la otra, si corresponde?
Esencialmente, la razón por la que la posición const
dentro de los especificadores antes de un asterisco no importa es que Kernighan y Ritchie definieron la gramática C de esa manera.
La razón por la que definieron la gramática de esta manera fue probablemente que su compilador de C analizaba la entrada de izquierda a derecha y terminaba de procesar cada token a medida que lo consumía. El consumo del *
token cambia el estado de la declaración actual a un tipo de puntero. Encontrar const
after *
significa que el const
calificador se aplica a una declaración de puntero; encontrarlo antes de *
que el calificador se aplique a los datos señalados.
Debido a que el significado semántico no cambia si el const
calificador aparece antes o después de los especificadores de tipo, se acepta de cualquier manera.
Un caso similar surge al declarar punteros de función, donde:
void * function1(void)
declara una función que devuelvevoid *
,void (* function2)(void)
declara un puntero de función a una función que devuelvevoid
.
Una vez más, lo que hay que tener en cuenta es que la sintaxis del lenguaje admite un analizador de izquierda a derecha.
La regla es:
const se aplica a lo que queda de él. Si no hay nada a la izquierda, entonces se aplica a lo que está a la derecha.
Prefiero usar const a la derecha de la cosa para que sea constante solo porque es la forma "original" en que se define const.
Pero creo que este es un punto de vista muy subjetivo.
Prefiero la segunda sintaxis. Me ayuda a realizar un seguimiento de "qué" es constante leyendo la declaración de tipo de derecha a izquierda:
Object * const obj; // read right-to-left: const pointer to Object
Object const * obj; // read right-to-left: pointer to const Object
Object const * const obj; // read right-to-left: const pointer to const Object
El orden de las palabras clave en una declaración no es tan fijo. Hay muchas alternativas al "único orden verdadero". Como esto
int long const long unsigned volatile i = 0;
o debería ser
volatile unsigned long long int const i = 0;
??