Regla 0x3017h: Orden canónico de calificadores: 'const tipo' en lugar de 'tipo const'
Memoria, punteros y tipos (0x30XX)
0x3017h: Orden canónico de calificadores: ‘const tipo’ en lugar de ‘tipo const’¶
Enunciado normativo¶
Los calificadores de tipo DEBEN escribirse antes del tipo base:
const int xy noint const x. El orden se aplica también a los punteros cuando el calificador corresponde al objeto apuntado:const char *p.
¿Por qué existe esta regla?¶
El problema¶
En C, const int e int const son exactamente equivalentes: los calificadores
de tipo pueden escribirse a cualquier lado del especificador. La libertad
sintáctica, sin embargo, produce inconsistencia cuando cada autor elige un orden
distinto. int const * y const int * describen el mismo tipo, pero obligan al
lector a comprobar que no hay diferencias.
La cátedra fija un orden canónico: el calificador primero. Así una declaración
se lee siempre igual y la atención puede concentrarse en el contrato (qué es
const) en lugar de en la forma. La regla se apoya en 0x3007h: Los argumentos de tipo puntero deben ser const siempre que la función no los modifique: el
contrato de sólo lectura se expresa con const al frente.
Consecuencias de violarla¶
| Tipo de consecuencia | Efecto concreto |
|---|---|
| Inconsistencia | Conviven const int e int const en el mismo módulo. |
| Legibilidad | El lector debe resolver equivalencias que no aportan información. |
| Ruido en revisiones | Los diffs muestran reordenamientos sin cambio semántico. |
| Confusión con punteros | int const * vs int * const exige leer con cuidado el orden. |
Fundamento en el estándar y en la cátedra¶
C11 §6.7.3 permite que los calificadores precedan o sigan al especificador de
tipo; la equivalencia es semántica, no sintáctica. La cátedra adopta
const tipo como convención institucional porque la lectura natural sitúa la
cualidad (“constante”) antes del sujeto (“entero”). Es una regla de estilo pura,
sin consecuencias en el comportamiento, y por eso tiene corrección automática.
Alcance y excepciones¶
Aplica a const, volatile y restrict cuando califican el tipo base.
Excepción importante: cuando el calificador se aplica al puntero y no al
objeto apuntado, la posición es forzosa: int *const p (el puntero es constante)
no equivale a const int *p (el objeto es constante). La regla sólo ordena el
calificador del tipo base; la distinción puntero/objeto sigue siendo esencial y
debe elegirse según el contrato.
Ejemplos exhaustivos¶
❌ Contraejemplo 1 — Calificador después del tipo¶
int const MAXIMO = 100;
char const *MENSAJE = "hola";Por qué falla: son válidas, pero se apartan del orden adoptado. int const e
int const * obligan al lector a adaptarse a una variante innecesaria. La forma
canónica es const int y const char *.
❌ Contraejemplo 2 — Mezcla de ambos órdenes en el mismo archivo¶
const int FILAS = 10;
int const COLUMNAS = 20;
void imprimir(char const *texto);
void reservar(const char *nombre);Por qué falla: el archivo usa dos convenciones para la misma idea. La lectura se
vuelve irregular y no hay una regla que el revisor pueda aplicar de forma
uniforme. Además, char const *texto dificulta ver que el objeto apuntado es
constante.
✅ Ejemplo conforme 1 — Calificador al frente¶
const int MAXIMO = 100;
const char *MENSAJE = "hola";
void imprimir(const char *texto);En todos los casos el calificador precede al tipo base. La declaración se lee “constante entero” y “puntero a carácter constante”, con el contrato al frente.
✅ Ejemplo conforme 2 — Puntero constante vs objeto constante¶
void procesar(const int *entrada, size_t n)
{
int *const cursor_base = (int *)entrada;
for (size_t i = 0; i < n; i++)
{
printf("%d\n", entrada[i]);
}
}const int *entrada indica que el objeto apuntado no se modifica; int *const cursor_base indica que el puntero no se reasigna. Son contratos distintos y el
orden canónico se aplica sólo al primero. El segundo conserva su forma forzosa.
⚠️ Casos límite¶
consten ambos lados:const int *const pes un puntero constante a entero constante; el orden del calificador base sigue siendoconst int.typedef: sientero_tes un alias,const entero_t xes correcto y el calificador se sitúa antes del alias.Arreglos de parámetros:
const int v[]equivale aconst int *vy respeta el orden.
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
gaff | gaff check archivo.c | Declaración con el calificador después del tipo base. |
gaff | gaff fix archivo.c | Reordena tipo const a const tipo automáticamente. |
gcc / clang | gcc -Wall -Wextra -std=c11 ... | No detecta el orden; ambas formas son equivalentes. |
Checklist de autocontrol¶
¿Escribí
const tipoy notipo const?¿Distinguí el calificador del objeto del calificador del puntero?
¿Mantuve un único orden en todo el archivo?
¿El
constsigue el contrato de 0x3007h: Los argumentos de tipo puntero deben ser const siempre que la función no los modifique?¿El
typedefno alteró la posición del calificador?
Reglas relacionadas¶
0x3007h: Los argumentos de tipo puntero deben ser const siempre que la función no los modifique — el contrato de sólo lectura usa
consten el tipo apuntado.0x3011h: Si una función recibe un puntero genérico para operaciones de solo lectura, la firma de la función debe utilizar const void* — la versión genérica
const void *.0x0103h: Las constantes (const o #define) deben nombrarse en MAYUSCULAS_SNAKE_CASE — las constantes también se nombran en mayúsculas.
0x300Ah: Utilizá cast explícito al convertir tipos de punteros — un cast no debe descartar el calificador así escrito.