Que tiene de util esto C
sintaxis: ¿usando declaraciones de función de estilo ‘K&R’?
int func (p, p2)
void* p;
int p2;
{
return 0;
}
Pude escribir esto en Visual Studios 2010beta
// yes, the arguments are flipped
void f()
{
void* v = 0;
func(5, v);
}
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;
}
Lo único que parece especificar es cuántos parámetros usa y el tipo de devolución. Supongo que los parámetros sin tipos son geniales, pero ¿por qué permitirlo y el int paranName
después del declarador de función? Es raro.
¿También es esto todavía C estándar?
La pregunta que está haciendo es realmente dos preguntas, no una. La mayoría de las respuestas hasta ahora trataron de cubrir todo con una respuesta genérica general “este es el estilo K&R”, mientras que, de hecho, solo una pequeña parte tiene algo que ver con lo que se conoce como estilo K&R (a menos que vea el lenguaje C completo como “estilo K&R” de una forma u otra 🙂
La primera parte es la extraña sintaxis utilizada en la función definición
int func(p, p2)
void *p;
int p2; /* <- optional in C89/90, but not in C99 */
{
return 0;
}
Esta es en realidad una definición de función de estilo K&R. Otra respuesta ha cubierto esto bastante bien. Y no hay mucho que decir, en realidad. La sintaxis está en desuso, pero aún es totalmente compatible incluso en C99 (excepto por la regla “sin int implícito” en C99, lo que significa que en C99 no puede omitir la declaración de p2
).
La segunda parte tiene poco que ver con el estilo K&R. Me refiero al hecho de que la función se puede llamar con argumentos “intercambiados”, es decir, no se verifica el tipo de parámetro en dicha llamada. Esto tiene muy poco que ver con la definición de estilo K&R per se, pero tiene mucho que ver con que su función no tenga prototipo. Verás, en C cuando declaras una función como esta
int foo();
en realidad declara una función foo
eso toma un número no especificado de parámetros de tipo desconocido. Puedes llamarlo como
foo(2, 3);
y como
j = foo(p, -3, "hello world");
y así sucesivamente (te haces una idea);
Solo la llamada con los argumentos adecuados “funcionará” (lo que significa que las demás producen un comportamiento indefinido), pero depende completamente de usted asegurarse de que sea correcta. No se requiere que el compilador diagnostique los incorrectos, incluso si de alguna manera conoce mágicamente los tipos de parámetros correctos y su número total.
En realidad, este comportamiento es un rasgo de lenguaje C. Una peligrosa, pero una característica al fin y al cabo. Te 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, mezcle diferentes tipos de funciones en una matriz “polimórfica” sin ningún tipo de conversión (sin embargo, los tipos de funciones variádicas no se pueden usar aquí). Nuevamente, los peligros inherentes de esta técnica son bastante obvios (no recuerdo haberla 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 K&R, no presenta un prototipo para la función. En lo que respecta al tipo de función, su func
definición declara func
como
int func();
es decir, no se declaran ni los tipos ni el número total de parámetros. En tu publicación original dices “… parece especificar cuántos parámetros usa …”. Hablando formalmente, ¡no lo hace! Después de su estilo K&R de dos parámetros func
definición que todavía puedes llamar func
como
func(1, 2, 3, 4, "Hi!");
y no habrá ninguna violación de restricción en él. (Normalmente, un compilador de calidad le dará una advertencia).
Además, un hecho que a veces se pasa por alto es que
int f()
{
return 0;
}
también es una definición de función de estilo K&R que no presenta un prototipo. Para hacerlo “moderno” tendrías que poner un explícito void
en la lista de parámetros
int f(void)
{
return 0;
}
Finalmente, contrariamente a la creencia popular, tanto las definiciones de funciones de estilo K&R como las declaraciones de funciones sin prototipos son totalmente compatibles con C99. El primero ha quedado en desuso 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. Aparentemente, la confusión proviene de la confusión terminológica popular: mucha gente llama a cualquier declaración de función “un prototipo”, mientras que, de hecho, “declaración de función” no es lo mismo que “prototipo”.
Esta es una sintaxis K&R C bastante antigua (anterior a ANSI/ISO C). Hoy en día, no debería usarlo más (como ya ha notado su principal desventaja: el compilador no verificará los tipos de argumentos por usted). El tipo de argumento en realidad por defecto es int
en tu ejemplo
En ese momento, se usaba esta sintaxis, a veces se encontraban funciones como
foo(p, q)
{
return q + p;
}
que en realidad era una definición válida, ya que los tipos para foo
, p
y q
por defecto a int
.
Esta es simplemente una sintaxis antigua, anterior a la sintaxis “ANSI C” con la que quizás esté más familiarizado. Se llama “K & R C“, típicamente.
Los compiladores lo admiten para que esté completo y, por supuesto, para poder manejar bases de código antiguas.
Esa es una reliquia de cuando C no tenía prototipos de funciones. Hace mucho tiempo, (creo) se suponía que las funciones volvían int
y se asumió que todos sus argumentos eran int
. No se realizó ninguna comprobación de los parámetros de la función.
Es mucho mejor usar prototipos de funciones en el lenguaje C actual.
Y usted deber utilícelos en C99 (C89 aún acepta la sintaxis anterior).
Y C99 requiere que se declaren funciones (posiblemente sin un prototipo). Si está escribiendo una nueva función desde cero, debe proporcionar una declaración… conviértala también en un prototipo: no pierde nada y obtiene una verificación adicional del compilador.
Esta es la sintaxis original de K&R antes de que C se estandarizara en 1989. C89 introdujo prototipos de funciones, tomados de C++, y dejó obsoleta la sintaxis de K&R. No hay razón para usarlo (y muchas razones para no hacerlo) en código nuevo.
Es un estilo más antiguo de declaraciones de funciones. Por favor vea este enlace. https://stackoverflow.com/questions/22500/cuáles-son-las-principales-diferencias-entre-ansi-c-y-kr-c texto del enlace
– Leónidas Tsampros
27 de octubre de 2009 a las 13:04