Espacios de nombres
Variantes

Definición de funciones

De cppreference.com

Una definición de función asocia el cuerpo de la función (una secuencia de declaraciones y expresiones) con el nombre de la función y la lista de parámetros. A diferencia de la declaración de funciones, las definiciones de funciones sólo se permiten en el ámbito del archivo (no hay funciones anidadas).

C soporta dos formas diferentes de definición de funciones:

especificadores-y-calificadores dec-lista-parametros cuerpo-de-función (1)
especificadores-y-calificadores dec-lista-identificadores lista-declaraciones cuerpo-de-función (2)

donde

especificadores-y-calificadores - una combinación de
dec-lista-parametros - un declarador para un tipo de función que utiliza una lista de parámetros para designar los parámetros de la función
dec-lista-identificadores - un declarador para un tipo de función que utiliza una lista de identificadores para designar los parámetros de la función
lista-declaraciones - secuencia de declaraciones que declaran cada identificador en dec-lista-identificadores. Estas declaraciones no pueden utilizar inicializadores y el único especificador de clase de almacenamiento permitido es register.
cuerpo-de-función - una sentencia compuesta que es una secuencia de declaraciones y sentencias entre paréntesis, que se ejecuta siempre que se llama a esta función
1) Definición de funciones de nuevo estilo (C89). Esta definición introduce la función en sí misma y 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.
int max(int a, int b)
{
    return a>b?a:b;
}

double g(void)
{
    return 0.1;
}
2) Definición de la función de estilo antiguo (K&R). Esta definición no se comporta como un prototipo y cualquier futura expresión de llamada de función realizará promociones de argumentos por defecto.
int max(a, b)
int a, b;
{
    return a>b?a:b;
}
double g()
{
    return 0.1;
}

Explicación

Al igual que con las declaraciones de funció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 declaraciones, debe ser un tipo de objeto completo que no sea un arreglo o bien de tipo void.

void f(char *s) { puts(s); } // el tipo de retorno es void
int sum(int a, int b) { return a+b: } // el tipo de retorno es int
int (*foo(const void *p))[3] { // el tipo de retorno es un puntero a un arreglo de 3 int2
    return malloc(sizeof(int[3]));
}

Al igual que con las declaraciones de función, si la clase de retorno sería cualificada cvr, se ajusta a su versión no cualificada con el fin de construir la clase de función.

(desde C17)

Al igual que con las declaraciones de función, los tipos de parámetros se ajustan de funciones a punteros y de matrices a punteros con el fin de construir el tipo de función y los calificadores cvr de nivel superior de todos los tipos de parámetros se ignoran con el fin de determinar el tipo de función compatible.

A diferencia de las declaraciones de función, los parámetros formales sin nombre no están permitidos, deben ser nombrados incluso si no se utilizan dentro de la función. La única excepción es la lista especial de parámetros (void)

int f(int, int); // declaración
// int f(int, int) { return 7; } // Error
int f(int a, int b) { return 7; } // definicion
int g(void) { return 8; } // esta bien, void no se declara como un parametro

Dentro del cuerpo de la función, cada parámetro es una expresión lvalue, tienen una duración de almacenamiento automática y un ámbito de bloque. La disposición de los parámetros en memoria (o si están almacenados en memoria) no está especificada: forma parte de la convención de llamada.

int main(int ac, char **av)
{
    ac = 2; // los parametros son lvalues
    av = (char *[]){"abc", "def", NULL};
    f(ac, av);
}

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

__func__

Dentro de cada cuerpo-de-función está disponible la variable especial predefinida __func__ con ámbito de aplicación de bloque y duración de almacenamiento estático, como si se definiera inmediatamente después de la llave de apertura mediante

static const char __func__[] = "nombre de la función";

Este identificador especial se utiliza a veces en combinación con las constantes de macro predefinidas __FILE__ y __LINE__, por ejemplo, por assert.

(desde C99)

Observaciones

La lista de argumentos debe estar explícitamente presente en el declarador, no puede ser heredada de un typedef

typedef int p(int q, int r); // p es un típo de función int(int, int)
p f { return q + r; } // Error

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

Además, la definición antigua no requería una declaración para cada parámetro de la lista-declaraciones. Cualquier parámetro cuya declaración faltaba tenía el tipo int

max(a, b) // a y b tienen el tipo int, el tipo de retorno tambien es int
{
    return a>b?a:b;
}
(hasta C99)

Referencias

  • Standard C11 (ISO/IEC 9899:2011):
  • 6.9.1 Function definitions (p: 156-158)
  • Standard C99 (ISO/IEC 9899:1999):
  • 6.9.1 Function definitions (p: 141-143)
  • Standard C89/C90 (ISO/IEC 9899:1990):
  • 3.7.1 Function definitions

Véase también

Documentación de C++ para Definición de funcion