Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Regla 0x0012h: Validador de formato canónico en firmas de punteros a función

Sintaxis y formato visual (0x00XX)

Universidad Nacional de Río Negro

0x0012h: Validador de formato canónico en firmas de punteros a función

Enunciado normativo

Las declaraciones y typedefs de punteros a función DEBEN seguir la forma canónica tipo (*identificador)(parámetros): el asterisco unido al nombre entre paréntesis, los paréntesis de la lista de parámetros pegados al cierre del nombre y sin espacios sueltos alrededor del *.

¿Por qué existe esta regla?

El problema

El declarador de un puntero a función es el más engañoso de C. El paréntesis no es decorativo: sin él, int *f(int, int) declara una función que devuelve int *, no un puntero a función. Los espacios dispersos (int (* f) (int, int), int ( *f )(int, int)) fragmentan el grupo (*identificador) que el lector necesita reconocer de un golpe. La forma canónica agrupa el asterisco con el nombre y deja pegado el paréntesis de parámetros: se lee “puntero llamado X a función que toma ... y devuelve tipo”.

Consecuencias de violarla

Tipo de consecuenciaEfecto concreto
CompilaciónColocar mal el paréntesis cambia el tipo y produce called object is not a function o incompatibilidad de tipos.
Bug silenciosoint *f(int, int) y int (*f)(int, int) son declaraciones distintas con semántica opuesta.
MantenibilidadUn typedef ilegible se propaga por todo el proyecto y se copia mal.
Revisióngaff marca el formato no canónico aunque el código compile.

Fundamento en el estándar y en la cátedra

ISO/IEC 9899:2011 §6.7.6.3 define los declaradores de función y §6.7.6.1 los de puntero; la combinación de ambos produce la sintaxis de puntero a función. La cátedra fija la forma canónica para que el typedef de un callback se lea igual en todos los archivos. Se articula con 0x0005h: El asterisco de los punteros debe declararse junto al identificador (asterisco junto al identificador) y con 0x3004h: Utilizá typedef para definir tipos de estructuras con el sufijo _t (sufijo _t para el alias).

Alcance y excepciones

Aplica a variables, parámetros, campos de struct y typedefs cuyo tipo sea puntero a función. No aplica a punteros comunes a datos (0x0005h: El asterisco de los punteros debe declararse junto al identificador) ni a punteros a puntero (0x0009h: Espaciado consistente en declaraciones de doble puntero (tipo **var)). No hay excepciones: también en prototipos en línea se usa la forma canónica.

Ejemplos exhaustivos

❌ Contraejemplo 1 — typedef con espacios dispersos

typedef int (* operacion_t )(int, int);

Por qué falla: hay un espacio entre ( y * y otro entre ) y (, de modo que el grupo (*operacion_t) queda partido y el alias se lee como si el asterisco y el nombre pertenecieran a frases distintas.

❌ Contraejemplo 2 — Variable y firma mal formateadas

int (* suma) (int, int);
int ( *resta )(int, int);

Por qué falla: en el primer caso el nombre queda separado de su lista de parámetros; en el segundo el asterisco flota. Ambos estilos se propagan a las llamadas y confunden al lector sobre qué es el nombre.

✅ Ejemplo conforme 1 — typedef canónico

typedef int (*operacion_t)(int, int);

Por qué cumple: el asterisco está pegado al nombre, el nombre entre paréntesis y la lista de parámetros pegada; el alias respeta el sufijo _t de 0x3004h: Utilizá typedef para definir tipos de estructuras con el sufijo _t.

✅ Ejemplo conforme 2 — Callback como parámetro y puntero global

static int aplicar(int (*operacion)(int, int), int a, int b)
{
    return operacion(a, b);
}

int (*comparar)(const void *, const void *) = NULL;

Por qué cumple: el parámetro operacion y la variable comparar siguen (*nombre)(...). Los parámetros const void * respetan 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* y la inicialización a NULL se alinea con 0x3008h: Los punteros nulos deben ser inicializados y comparados con NULL, no con 0.

⚠️ Casos límite

Cómo detectarla

HerramientaComandoSeñal
gaffgaff check archivo.cMarca espacios alrededor del * o entre ) y ( en punteros a función.
gcc / clanggcc -Wall -Wextra -Wpedantic -std=c11 -c archivo.cAdvierte incompatibilidades de tipo entre firmas distintas.
Revisión manualBuscar (* y * ) con espacios intermedios.

Checklist de autocontrol

Reglas relacionadas