Espacios de nombres
Variantes
Acciones

Declaración de funciones

De cppreference.com
< c‎ | language

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

Contenido

[editar] Sintaxis

En la gramática de la declaración de una función, la secuencia de especificaciones de tipo, posiblemente modificada por el declarante, designa el tipo de retorno (que puede ser de cualquier tipo que no sea un arreglo o un tipo de función), y el "declarante" tiene una de dos formas:

declarador-nopunt ( lista-parametros ) (1)
declarador-nopunt ( lista-identificadores(opcional) ) (2)

donde

declarador-nopun - cualquier declarador excepto el de puntero sin paréntesis. El identificador contenido en este declarador es el identificador que se convierte en el designador de la función.
lista-parametros - o bien el termino clave void o una lista separada por comas de parámetros, que puede terminar con un parámetro de elipsis
lista-identificadores - lista de identificadores separados por comas (sólo si este declarador se utiliza como parte de la definición de función de estilo antiguo), debe omitirse para las declaraciones de estilo antiguo que no sean definiciones.
1) Declaración de función de nuevo estilo (C89). Esta declaración introduce el propio designador de función y también sirve como prototipo de función para cualquier expresión de llamada de función futura, forzando conversiones de expresiones de argumento a los tipos de parámetro declarados y controlando en tiempo de compilación el número de argumentos.
int max(int a, int b);      // Declaracion
int n = max(12.01, 3.14);   // Esta bien, es una conversión de double a int
2) Declaración de la función de estilo antiguo (K&R). Esta declaración no se comporta como un prototipo y cualquier expresión de llamada de función futura realizará promociones de argumentos por defecto e invocará un comportamiento indefinido si el número de argumentos no coincide con el número de parámetros.
int max();
int n = max(true, (char)'a');   // Llama a max con dos argumentos int (después de promocionarse)
int n = max(12.01f, 3.14);      // Llama a max con dos argumentos double (después de promocionarse)
int max(a, b) 
int a, b; { return a>b?a:b; }   // La definición espera ints; la segunda llamada es indefinida

[editar] Explicación

El tipo de retorno de la función, determinado por el especificador de tipo en los especificadores-y-calificadores y posiblemente modificado por el declarador como es habitual en las declarations, debe ser un tipo de objeto completo que no sea un arreglo o el tipo void.

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 un puntero a un arreglo de 3 int

El tipo de retorno de una función no puede ser cualificado cvr: cualquier tipo de retorno cualificado se ajusta a su versión no cualificada con el fin de construir el tipo de función:

double const foo(void) { return 0.; } // Declara a la funcion de tipo double(void)
double (*foop)(void) = foo;           // Esta bien, foop es un puntero a double(void)
double const (*foopc)(void) = foop;   // Esta bien, foopc es otro puntero a  double(void)
(desde C17)

Los declaradores de función pueden combinarse con otros declaradores siempre y cuando 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 sólo para funciones
typedef int array_t[3];
array_t a, h(); // Error: el tipo arreglo 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 alcance de archivo y enlace externo, a menos que se utilice static o se vea una declaración estática anterior. Si la declaración se produce dentro de otra función, el identificador tiene un alcance de bloque (y también un enlace interno o externo).

int main(void)
{
    int f(int); // Enlace externo, alcance del archivo
    f(1);       // La definición debe estar disponible en algún lugar del programa
}

No es necesario nombrar los parámetros de una declaración que no forman parte de una definición de función:

int f(int, int); // Declaracion
// int f(int, int) { return 7; } // Error, los parámetros deben ser nombrados en las definiciones

Cada parámetro de una lista-parametros 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 forma parte de una definición de función)
int f(int, double);         // Esta bien
int g(int a, double b);     // Tambien esta bien
int f(int, double) { return 1; } // Error: la definición debe nombrar los parámetros
int f(static int x);        // Error
int f(int [static 10]);     // Esta bien (el índice del arreglo estático no es un especificador de clase de almacenamiento)
  • cualquier parámetro del tipo de arreglo se ajusta al tipo de puntero correspondiente, que puede calificarse si hay calificadores entre los corchetes del declarador de arreglo. (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 del tipo de función se ajusta al tipo de puntero correspondiente
int f(char g(double));      // Declara int f(char (*g)(double))
int h(int(void));           // Declara int h(int (*)(void))
int f(int, ...);
  • no pueden tener el tipo void}. (pero puede tener un puntero a void). La lista de parámetros especiales que consiste enteramente en la palabra clave void se utiliza para declarar funciones que no toman ningún parámetro.
int f(void);    // Esta bien
int g(void x);  // Error
  • cualquier identificador que aparezca en una lista de parámetros que pueda ser tratado como un nombre de typedef o como un nombre de parámetro es tratado como un nombre de typedef: int f(size_t, uintptr_t) es analizado como un nuevo declarador de estilo para una función que toma dos parámetros sin nombre de tipo size_t y uintptr_t, no un declarador de estilo antiguo que comienza la definición de una función tomando dos parámetros llamados "size_t" y "uintptr_t".
  • los parámetros pueden tener tipo incompleto y puede usar la notación VLA [*] (desde C99) (excepto que en una definición de función, los tipos de parámetros después del ajuste de arreglo a puntero y funcion a puntero deben estar completos)

Véase el operador de llamada de función para otros detalles sobre la mecánica de una llamada de función y return para el retorno de las funciones.

[editar] Observaciones

A diferencia de C++, los declaradores f() y f(void) tienen diferentes significados: el declarador f(void) es un nuevo estilo (prototipo) de declarador que declara una función que no toma ningún parámetro. El declarador f() es un declarador de estilo antiguo (K&R) que declara una función que toma un número no especificado de parámetros (a menos que se utilice en una definición de función de estilo antiguo)

int f(void); // declaracion que no toma parametros
int g(); // declaracion que toma un numero desconocido de parametros
 
int main(void) {
    f(1); // Error de compilación
    g(2); // comportamiento indefinido
}
 
int f(void) { return 1; ) // definicion real
int g(a,b,c,d) int a,b,c,d; { return 2; } // definicion real

A diferencia de una definición de función, la lista de parámetros puede ser heredada de un typedef

typedef int p(int q, int r); // p es una funcion de tipo int(int, int)
p f; // Declara int f(int, int)

En C89, los especificadores-y-calificadores era opcionales, y si se omiten, el tipo de retorno de la función por defecto es int (posiblemente modificado por el declarador).

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

[editar] Referencias

  • C17 standard (ISO/IEC 9899:2018):
  • 6.7.6.3 Function declarators (including prototypes) (p: 96-98)
  • Standard C11 (ISO/IEC 9899:2011):
  • 6.7.6.3 Function declarators (including prototypes) (p: 133-136)
  • Standard C99 (ISO/IEC 9899:1999):
  • 6.7.5.3 Function declarators (including prototypes) (p: 118-121)
  • Standard C89/C90 (ISO/IEC 9899:1990):
  • 3.5.4.3 Function declarators (including prototypes)

[editar] Véase también

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