2009-10-27 20 views
55

¿Qué es útil acerca de esta sintaxis C - utilizando las declaraciones de función de estilo 'K & R'?Sintaxis alternativa (K & R) C para la declaración de función frente a prototipos

int func (p, p2) 
    void *p; 
    int p2; 
{ 
    return 0; 
} 

que fue capaz de escribir esto en Estudios Visuales 2010beta

//yes the params are flipped 
void f() 
{ 
    void *v=0; 
    func(5,v); 
} 

que no entiendo. ¿Cuál es el punto de esta sintaxis? Puedo escribir:

int func (p, p2) 
    int p2; 
{ 
    return 0; 
} 
//and write 
int func (p, p2) 
{ 
    return 0; 
} 

La única cosa que parece indicar es la cantidad de parámetros que utiliza y el tipo de retorno. Supongo que los parámetros sin tipos son geniales, pero ¿por qué permitirlo y el int paranName después del declarador de funciones? Es raro.

También es esto todavía estándar C?

Respuesta

124

La pregunta que hace es realmente dos preguntas, no una. La mayoría de las respuestas intentaron cubrir todo el asunto con una manta genérica "esto es K & estilo R" respuesta, mientras que de hecho, solo una pequeña parte tiene algo que ver con lo que se conoce como K & estilo R (a menos que veas todo el lenguaje C como "K & R-estilo" de una manera u otra :)

la primera parte es la sintaxis extraña utilizado en función de la definición

int func(p, p2) 
void *p; 
int p2; /* <- optional in C89/90, but not in C99 */ 
{ 
    return 0; 
} 

Ésta es en realidad una K & Definición de función estilo R Otra respuesta ha cubierto esto bastante bien. Y no hay mucho para eso, en realidad. La sintaxis está en desuso, pero aún totalmente compatible incluso en C99 (excepto para la regla "no implicit imp" en C99, lo que significa que en C99 no puede omitir la declaración de p2).

La segunda parte tiene poco que ver con K & estilo R. Me refiero al hecho de que la función puede invocarse con argumentos "intercambiados", es decir, que no se realiza ninguna verificación de tipo de parámetro en dicha llamada. Esto tiene muy poco que ver con la definición de estilo R de K & per se, pero tiene todo que ver con que su función no tenga prototipo. Usted ve, en C cuando se declara una función como esta

int foo(); 

que en realidad declara una función que toma fooun número indeterminado de parámetros de tipo desconocido. Se le puede llamar como

foo(2, 3); 

y como

j = foo(p, -3, "hello world"); 

ans así sucesivamente (se entiende la idea);

Solo la llamada con argumentos correctos "funcionará" (lo que significa que los demás producen un comportamiento indefinido), pero depende completamente de usted asegurar su corrección. El compilador no está obligado a diagnosticar los incorrectos, incluso si de alguna manera sabe mágicamente los tipos de parámetros correctos y su número total.

En realidad, este comportamiento es una característica del lenguaje C. Una peligrosa, pero una característica sin embargo. Se le permite hacer algo como esto

void foo(int i); 
void bar(char *a, double b); 
void baz(void); 

int main() 
{ 
    void (*fn[])() = { foo, bar, baz }; 
    fn[0](5); 
    fn[1]("abc", 1.0); 
    fn[2](); 
} 

es decir, mezclar diferentes tipos de funciones en una matriz "polimórfica" sin ningún tipo de typecasts (tipos de función variadic no se pueden utilizar aquí, sin embargo). Nuevamente, los peligros inherentes de esta técnica son bastante obvios (no recuerdo haberlo usado nunca, pero puedo imaginar dónde puede ser útil), pero eso es C después de todo.

Finalmente, el bit que vincula la segunda parte de la respuesta con la primera. Cuando realiza una definición de función de estilo R K &, no introduce un prototipo para la función. En lo que se refiere a tipo de función, su definición func declara func como

int func(); 

es decir, ninguno de los tipos ni el número total de parámetros son declarados. En tu publicación original dices "... parece especificar cuántos params usa ...".Formalmente hablando, ¡no es así! Después de la de dos parámetros K & R-estilo func definición todavía se puede llamar como func

func(1, 2, 3, 4, "Hi!"); 

y no habrá ninguna violación de la restricción en el mismo. (Normalmente, un compilador de calidad le dará una advertencia).

También, a veces se olvida un hecho es que

int f() 
{ 
    return 0; 
} 

es también una definición de función de estilo R K & que no introduzca un prototipo. Para que sea más "moderna" que tendría que poner explícita void en la lista de parámetros

int f(void) 
{ 
    return 0; 
} 

último, contrariamente a la creencia popular, tanto K & definiciones de funciones de tipo I y declaraciones de funciones no-prototipos son totalmente compatible con C99. El primero ha quedado obsoleto desde C89/90, si no recuerdo mal. C99 requiere que la función se declare antes del primer uso, pero no se requiere que la declaración sea un prototipo. La confusión aparentemente se deriva de la popular confusión terminológica: muchas personas llaman a cualquier declaración de la función "prototipo", mientras que de hecho "declaración de la función" no es lo mismo que "prototipo".

+6

muy bien explicado, esp. la parte "función sin prototipo". –

+1

Pero, ¿cuál es la diferencia ahora entre una función varargs y una no prototipada? – Sebastian

+1

@Sebastian Godelet varargs son innecesariamente estrictas. Por ejemplo, llamar a una función vararg con una int, y abrirla como bytes no es válido. Entonces, definir una función con solo parámetros vararg. – YoYoYonnY

4

Esto es simplemente una sintaxis antigua, que es anterior a la sintaxis "ANSI C" con la que podría estar más familiarizado. Se llama "K&R C", por lo general.

Los compiladores lo admiten completo, y para poder manejar antiguas bases de código, por supuesto.

17

Esto es bastante antiguo K & sintaxis R C (anteriores a ANSI/ISO C). Hoy en día, ya no deberías usarlo (ya que ya has notado su gran desventaja: el compilador no verificará los tipos de argumentos por ti). El tipo de argumento se establece de manera predeterminada en int en su ejemplo.

En ese momento, se utilizó esta sintaxis, uno a veces se encontraría funciones como

foo(p, q) 
{ 
    return q + p; 
} 

que era en realidad una definición válida, ya que los tipos de foo, p y q por defecto a int.

1

Eso es una reliquia de cuando C no tenía prototipos de funciones. En aquel entonces, (creo) se suponía que las funciones devolvían int y se suponía que todos sus argumentos eran int. No se realizó ninguna comprobación en los parámetros de la función.

Es mucho mejor utilizar prototipos de función en el lenguaje C actual.
Y usted debe usar en C99 (C89 todavía acepta la sintaxis anterior).

Y C99 requiere que se declaren las funciones (posiblemente sin un prototipo). Si está escribiendo una nueva función desde cero, debe proporcionar una declaración ... también conviértalo en un prototipo: no pierde nada y obtiene una verificación adicional del compilador.

+3

Incorrecto. En C99, las funciones deben declararse explícitamente antes de llamarlas. Sin embargo, C99 no requiere una declaración prorotipada. C99 es totalmente compatible con la sintaxis de K & R con un cambio: se ha eliminado la regla 'int' implícita. – AnT

+0

Tienes razón, gracias. Editado mi respuesta. – pmg

1

Esta es la sintaxis original K & R antes de que C se estandarizara en 1989. C89 introdujo prototipos de funciones, tomados de C++, y desaprobó la sintaxis R de K &.No hay ninguna razón para usarlo (y muchas razones para no hacerlo) en un código nuevo.

Cuestiones relacionadas