Podemos hacer esto
if(condition) doThis();y esto
while(condition) doThat();pero no esto
int giveMeFive() return 5; // Error: expected a '{'¿Por qué no?
Soy consciente de que la gramática del idioma requiere { y } en las definiciones de funciones. Estoy preguntando sobre el fundamento de la diferencia entre declaraciones condicionales (que no requieren llaves) y definiciones de funciones (que sí).
La razón parece ser principalmente histórica.
Antes del estándar ANSI C de 1989, C no tenía prototipos. Los parámetros de tipo int podrían definirse implícitamente; los parámetros de tipos distintos de int tenían que definirse explícitamente, antes de la apertura { .
Por ejemplo, donde en C moderno podríamos escribir:
double sum(double x, double y) { return x + y; }en pre-ANSI (K&R) C teníamos que escribir:
double sum(x, y) double x; double y; { return x + y; }El cuerpo de la función podría comenzar con una declaración de una variable local:
double sum(x, y) double x; double y; { double z; /* ... */ } Se necesitaba el { de apertura para separar las definiciones de parámetros del cuerpo de la función, y el } de cierre para coincidir con el { de apertura.
(Esta sintaxis todavía está permitida, pero está obsoleta, en C moderno; no está permitida en C++).
Cuando se agregaron prototipos al lenguaje, no hubo ninguna razón particular para permitir la omisión de { y } en las definiciones de funciones.
La respuesta trivial es que eso es lo que requiere la gramática del lenguaje. La sintaxis para una definición de función es:
especificadores-declaración declarador lista-declaración opt declaración-compuesta
donde una declaración compuesta consta de { , seguida de 0 o más declaraciones y sentencias, seguidas de } . Esta es la única producción de sintaxis que requiere una declaración compuesta ; hay muchos otros que simplemente requieren una declaración .
Curiosamente, en el lenguaje predecesor de C, llamado B ( documentado aquí ), la sintaxis de una definición de función era:
name ( arguments ) statement La declaración generalmente era una declaración compuesta (un bloque delimitado por { y } ), pero no era necesario que lo fuera. B no requería, ni siquiera permitía, argumentos y variables para tener sus tipos especificados, por lo que no había necesidad de tener una sintaxis particular para separar la lista de argumentos entre paréntesis del cuerpo de la función. En la primera referencia de C que puedo encontrar ( esta, de 1974 ), la sintaxis de una definición de función se había cambiado para requerir una declaración compuesta, probablemente para acomodar la adición de declaraciones de parámetros.
Si estuviera permitido, no habría diferencia entre una declaración de función:
void a();y una definición de función para una función que no hace nada:
void a() ;Seguramente agregaría más problemas que ganancias.
Creo que el problema es que es difícil distinguir esta construcción
int giveMeFive() return 5;y esta construccion
int giveMeFive() //; ^^^ return 5;Eso es si el programador cometió un error tipográfico.
Actualmente el compilador emite un error. Pero, ¿qué hacer si se permite tal definición de función? Esto hará que el programa sea mucho menos claro.
De hecho, podría usarse como una función en línea simplificada
T function( parameter-list ) return expression;Sin embargo, colocar un punto y coma entre el encabezado de la función y su cuerpo
T function( parameter-list ) ; return expression;cambia el symantic y hace que el código no sea claro.
La diferencia, por ejemplo, con una declaración while es que un punto y coma después de una declaración while como esta
while( condition );no cambia la definición de la construcción. En cualquier caso, es la instrucción while.
Sin embargo, en relación con la definición de la función, la situación es diferente.