Regla 0x3007h: Los argumentos de tipo puntero deben ser const siempre que la función no los modifique
Memoria, punteros y tipos (0x30XX)
0x3007h: Los argumentos de tipo puntero deben ser const siempre que la función no los modifique¶
Enunciado normativo¶
Todo parámetro de tipo puntero cuyo objeto apuntado NO sea modificado por la función DEBE declararse con
constsobre el tipo apuntado (const T *param). El calificador DEBE ubicarse antes del tipo base, conforme a 0x3017h: Orden canónico de calificadores: ‘const tipo’ en lugar de ‘tipo const’.
¿Por qué existe esta regla?¶
El problema¶
const en un parámetro de puntero es un contrato verificable por el compilador:
promete que la función no escribirá a través de ese puntero. Sin el calificador,
el llamador no distingue una función que lee de una que modifica, y además no
puede pasarle datos const ni literales. El calificador no limita al llamador:
lo habilita a usar sus datos de sólo lectura con más funciones.
Consecuencias de violarla¶
| Tipo de consecuencia | Efecto concreto |
|---|---|
| Contrato débil | El llamador no sabe si sus datos serán alterados. |
| Restricción inversa | No se pueden pasar literales de cadena ni objetos const a la función. |
| Bug silencioso | Una escritura accidental modifica datos del llamador sin advertencia. |
Fundamento en el estándar y en la cátedra¶
C11 §6.7.3 define el calificador const: un lvalue const no puede modificarse.
Aplicado al tipo apuntado, impide escrituras a través del puntero. La cátedra lo
exige como estilo defensivo: el contrato debe ser lo más restrictivo posible.
Alcance y excepciones¶
Aplica a parámetros de puntero, incluidos punteros a structs y a void. No
aplica cuando la función modifica el objeto apuntado, ni al propio puntero cuando
se reasigna localmente (T *const, otro contrato).
Ejemplos exhaustivos¶
❌ Contraejemplo 1 — Función de impresión sin const¶
void imprimir_texto(char *cadena)
{
printf("%s\n", cadena);
}
imprimir_texto("hola");Por qué falla: aunque imprimir_texto no escribe, su firma no lo dice. Pasar el
literal "hola" (de tipo char[5], almacenado en memoria de sólo lectura) no
compila en C moderno porque el parámetro no es const. El contrato quedó más
restrictivo que la realidad.
❌ Contraejemplo 2 — Recorrido que no modifica pero no es const¶
size_t contar_pares(int *valores, size_t cantidad)
{
size_t pares = 0;
for (size_t i = 0; i < cantidad; i++)
{
if (valores[i] % 2 == 0)
{
pares++;
}
}
return pares;
}Por qué falla: la función sólo lee valores, pero su firma sugiere que podría
modificarlo. El llamador que tenga un arreglo const no podrá usarla, y quien
lea la firma deberá revisar el cuerpo para confiar.
✅ Ejemplo conforme 1 — const sobre el tipo apuntado¶
void imprimir_texto(const char *cadena)
{
printf("%s\n", cadena);
}
size_t contar_pares(const int valores[], size_t cantidad);Ambas firmas declaran explícitamente que no modifican lo apuntado: la primera con
cuerpo y la segunda como prototipo. El compilador verifica el contrato y el
llamador puede pasar datos const o literales.
✅ Ejemplo conforme 2 — Distinguir entrada de salida¶
void sumar_vectores(const double *a, const double *b, double *resultado,
size_t cantidad)
{
for (size_t i = 0; i < cantidad; i++)
{
resultado[i] = a[i] + b[i];
}
}Los dos operandos de entrada son const; el destino no lo es porque se escribe.
La firma completa comunica el flujo de datos sin leer el cuerpo. Si el destino
fuera también const, el compilador rechazaría la asignación.
⚠️ Casos límite¶
consty el puntero:const char *pprotege el carácter;char *const pprotege la variablep. No son intercambiables. La regla habla del objeto apuntado, no del puntero.consten la implementación: si un parámetro se declaraconsten la cabecera, la definición debe repetirlo; si no, el compilador avisa de declaraciones incompatibles.Datos que sí mutan: un acumulador de tipo
size_t *es salida y no llevaconst; documentalo con 0x3006h: Documentá la propiedad de los recursos al utilizar punteros.
Cómo detectarla¶
| Herramienta | Comando | Señal |
|---|---|---|
gaff | gaff check archivo.c | Parámetro de puntero sin const en función que no escribe lo apuntado. |
gcc / clang | gcc -Wall -Wextra -Wwrite-strings -Wcast-qual ... | discarding 'const' qualifier al llamar con datos de sólo lectura. |
cppcheck | cppcheck --enable=style archivo.c | Parameter 'x' can be declared as pointer to const. |
Checklist de autocontrol¶
¿La función modifica el objeto apuntado? Si no, ¿es
const?¿Todos los parámetros de entrada son
const?¿Los parámetros de salida quedaron sin
const?¿El
constestá antes del tipo base?¿La cabecera y el
.cdeclaran el mismo calificador?
Reglas relacionadas¶
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 para punteros
void.0x3017h: Orden canónico de calificadores: ‘const tipo’ en lugar de ‘tipo const’ — orden canónico
const tipo.0x3006h: Documentá la propiedad de los recursos al utilizar punteros — propiedad y préstamo se documentan junto al
const.0x2006h: Mantené el alcance de las variables al mínimo posible — el mínimo privilegio también se expresa en los calificadores.