Sintaxis alternativa (K&R) C para la declaración de funciones versus prototipos

7 minutos de lectura

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?

  • 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

avatar de usuario
Hormiga

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”.

  • Pero, ¿cuál es la diferencia ahora entre una función varargs y una sin prototipo?

    – Sebastián

    26 de septiembre de 2013 a las 9:09

  • Los varargs de @Sebastian Godelet son innecesariamente estrictos. Por ejemplo, llamar a una función vararg con un int y mostrarla como bytes no es válido. También lo es definir una función con solo parámetros vararg.

    – yyny

    04/06/2016 a las 21:57


  • Las funciones de @Sebastian Vararg en realidad se pueden llamar correctamente con diferentes números de parámetros, como printf. Las funciones sin prototipos se pueden llamar correctamente solo con un cierto número fijo de argumentos, pero el compilador no sabe cuál y no puede verificar (así que debe hacerlo).

    – no-un-usuario

    9 de abril de 2019 a las 6:28

  • Supongo que es hora de cambiar supported even in C99 . C99 to C11. :-).

    – sjsam

    17 de abril de 2019 a las 12:45

  • Recuerdo que cuando comencé con C en Amstrad PCW, estaba confundido porque el compilador usaba esa sintaxis de declaración de funciones anterior, pero el libro de tutoriales que tenía usaba la sintaxis más nueva. Esos eran los dias…hace 25 años…!

    –Andrew Truckle

    25 de junio de 2019 a las 4:27

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, py 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.

avatar de usuario
pmg

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.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad