Function declarations
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 |
int max(int a, int b); // declaration int n = max(12.01, 3.14); // OK, conversion from double to int
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)
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
- el único especificador de clase de almacenamiento permitido para parámetros es register , y se ignora en declaraciones de funciones que no son definiciones
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
|