Namespaces
Variants

Function declarations

From cppreference.net

Una declaración de función introduce un identificador que designa una función y, opcionalmente, especifica los tipos de los parámetros de la función (el prototipo ). Las declaraciones de función (a diferencia de las definiciones ) pueden aparecer tanto en el ámbito de bloque como en el ámbito de archivo.

Contenidos

Sintaxis

En la gramática de declaraciones de una declaración de función, la secuencia type-specifier , posiblemente modificada por el declarador, designa el tipo de retorno (que puede ser cualquier tipo excepto array o tipo función), y el declarador tiene una de tres (until C23) dos (since C23) formas:

noptr-declarator ( parameter-list ) attr-spec-seq (opcional) (1)
noptr-declarator ( identifier-list ) attr-spec-seq (opcional) (2) (hasta C23)
noptr-declarator ( ) attr-spec-seq (opcional) (3)

donde

noptr-declarator - cualquier declarador excepto declarador de puntero sin paréntesis. El identificador contenido en este declarador es el que se convierte en el designador de función.
parameter-list - ya sea la palabra clave única void o una lista separada por comas de parámetros , que puede terminar con un parámetro de elipsis
identifier-list - lista separada por comas de identificadores, solo posible si este declarador se usa como parte de una definición de función de estilo antiguo
attr-spec-seq - (C23) una lista opcional de atributos , aplicados al tipo de función
1) Declaración de función de estilo nuevo (C89). Esta declaración introduce tanto el designador de función en sí mismo como también sirve como prototipo de función para cualquier futura expresión de llamada a función , forzando conversiones de expresiones de argumento a los tipos de parámetros declarados y verificaciones en tiempo de compilación para el número de argumentos.
int max(int a, int b); // declaration
int n = max(12.01, 3.14); // OK, conversion from double to int
2) (hasta C23) Definición de función al estilo antiguo (K&R). Esta declaración no introduce un prototipo y cualquier futura expresión de llamada a función realizará promociones de argumentos predeterminadas e invocará comportamiento indefinido si el número de argumentos no coincide con el número de parámetros.
int max(a, b)
    int a, b; // definition expects ints; the second call is undefined
{
    return a > b ? a : b;
}
int n = max(true, (char)'a'); // calls max with two int args (after promotions)
int n = max(12.01f, 3.14); // calls max with two double args (after promotions)
3) Declaración de función sin prototipo. Esta declaración no introduce un prototipo (until C23) . Una nueva declaración de función equivalente a parameter-list void (since C23) .

Explicación

El tipo de retorno de la función, determinado por el especificador de tipo en specifiers-and-qualifiers y posiblemente modificado por el declarator como es habitual en declarations , debe ser un tipo de objeto no-array o el tipo void . Si la declaración de la función no es una definición, el tipo de retorno puede ser incompleto . El tipo de retorno no puede estar calificado cvr: cualquier tipo de retorno calificado se ajusta a su versión no calificada para el propósito de construir el tipo de función.

void f(char *s);                    // el tipo de retorno es void
int sum(int a, int b);              // el tipo de retorno de sum es int
int (*foo(const void *p))[3];       // el tipo de retorno es puntero a arreglo de 3 int
double const bar(void);             // declara función de tipo double(void)
double (*barp)(void) = bar;         // OK: barp es un puntero a double(void)
double const (*barpc)(void) = barp; // OK: barpc también es un puntero a double(void)

Los declaradores de función pueden combinarse con otros declaradores siempre que puedan compartir sus especificadores de tipo y calificadores

int f(void), *fip(), (*pfi)(), *ap[3]; // declara dos funciones y dos objetos
inline int g(int), n; // Error: el calificador inline es solo para funciones
typedef int array_t[3];
array_t a, h(); // Error: el tipo array no puede ser un tipo de retorno para una función

Si una declaración de función aparece fuera de cualquier función, el identificador que introduce tiene ámbito de archivo y enlace externo , a menos que se utilice static o sea visible una declaración static anterior. Si la declaración ocurre dentro de otra función, el identificador tiene ámbito de bloque (y también enlace interno o externo).

int main(void)
{
    int f(int); // enlace externo, ámbito de bloque
    f(1); // la definición debe estar disponible en algún lugar del programa
}

Los parámetros en una declaración que no es parte de una definición de función (until C23) no necesitan tener nombre:

int f(int, int); // declaración
// int f(int, int) { return 7; } // Error: los parámetros deben tener nombre en las definiciones
// Esta definición está permitida desde C23

Cada parámetro en una parameter-list es una declaración que introduce una única variable, con las siguientes propiedades adicionales:

  • el identificador en el declarador es opcional (excepto si esta declaración de función es parte de una definición de función) (until C23)
int f(int, double); // OK
int g(int a, double b); // también OK
// int f(int, double) { return 1; } // Error: la definición debe nombrar parámetros
// Esta definición está permitida desde C23
int f(static int x); // Error
int f(int [static 10]); // OK (el static del índice del array no es un especificador de clase de almacenamiento)
  • cualquier parámetro de tipo array se ajusta al tipo puntero correspondiente , el cual puede estar calificado si hay calificadores entre los corchetes del declarador de array (desde C99)
int f(int[]); // declara int f(int*)
int g(const int[10]); // declara int g(const int*)
int h(int[const volatile]); // declara int h(int * const volatile)
int x(int[*]); // declara int x(int*)
  • cualquier parámetro de tipo función se ajusta al tipo puntero correspondiente
int f(char g(double)); // declara int f(char (*g)(double))
int h(int(void)); // declara int h(int (*)(void))
  • la lista de parámetros puede terminar con , ... o ser ... (desde C23) , consulte funciones variádicas para más detalles.
int f(int, ...);
  • los parámetros no pueden tener tipo void (pero pueden tener tipo puntero a void). La lista de parámetros especial que consiste enteramente en la palabra clave void se utiliza para declarar funciones que no toman parámetros.
int f(void); // Correcto
int g(void x); // Error
  • cualquier identificador que aparezca en una lista de parámetros que pueda tratarse como un nombre typedef o como un nombre de parámetro se trata como un nombre typedef: int f ( size_t , uintptr_t ) se analiza como un declarador de nuevo estilo para una función que toma dos parámetros sin nombre de tipo size_t y uintptr_t , no como un declarador de estilo antiguo que comienza la definición de una función que toma dos parámetros llamados " size_t " y " uintptr_t ".
  • los parámetros pueden tener tipo incompleto y pueden usar la notación VLA [ * ] (since C99) (excepto que en una definición de función , los tipos de parámetros después del ajuste de array-a-puntero y función-a-puntero deben ser completos).

Las secuencias de especificadores de atributos también pueden aplicarse a parámetros de función.

(desde C23)

Consulte function call operator para otros detalles sobre la mecánica de una llamada a función y return para regresar desde funciones.

Notas

A diferencia de C++, los declaradores f ( ) y f ( void ) tienen diferente significado: el declarador f ( void ) es un declarador de nuevo estilo (prototipo) que declara una función que no toma parámetros. El declarador f ( ) es un declarador que declara una función que toma un número no especificado de parámetros (a menos que se use en una definición de función)

int f(void); // declaration: takes no parameters
int g(); // declaration: takes unknown parameters
int main(void) {
    f(1); // compile-time error
    g(2); // undefined behavior
}
int f(void) { return 1; } // actual definition
int g(a,b,c,d) int a,b,c,d; { return 2; } // actual definition
(hasta C23)

A diferencia de una function definition , la lista de parámetros puede heredarse de un typedef

typedef int p(int q, int r); // p es un tipo de función int(int, int)
p f; // declara int f(int, int)

En C89, especificadores-y-calificadores era opcional, y si se omitía, el tipo de retorno de la función por defecto era int (posiblemente modificado por el declarador ).

*f() { // función que retorna int*
   return NULL;
}
(hasta C99)

Informes de defectos

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares de C publicados anteriormente.

DR Aplicado a Comportamiento publicado Comportamiento correcto
DR 423 C89 el tipo de retorno podría estar calificado el tipo de retorno está implícitamente descalificado

Referencias

  • Estándar C23 (ISO/IEC 9899:2024):
  • 6.7.7.4 Declaradores de función (incluyendo prototipos) (p: 130-132)
  • Estándar C17 (ISO/IEC 9899:2018):
  • 6.7.6.3 Declaradores de función (incluyendo prototipos) (p: 96-98)
  • Estándar C11 (ISO/IEC 9899:2011):
  • 6.7.6.3 Declaradores de función (incluyendo prototipos) (p: 133-136)
  • Estándar C99 (ISO/IEC 9899:1999):
  • 6.7.5.3 Declaradores de función (incluyendo prototipos) (p: 118-121)
  • Estándar C89/C90 (ISO/IEC 9899:1990):
  • 3.5.4.3 Declaradores de función (incluyendo prototipos)

Véase también

Documentación de C++ para Declaración de función