2010-10-29 16 views
5

Estoy siguiendo una guía para aprender las maldiciones, y todo el código C dentro de los prototipos funciona antes de main(), luego los define después. En mis aprendizajes en C++, había escuchado sobre el prototipado de funciones pero nunca lo había hecho, y hasta donde yo sé, no hace una gran diferencia en cómo se compila el código. ¿Es la elección personal de un programador más que cualquier otra cosa? Si es así, ¿por qué estaba incluido en C?¿Cuál es el punto de la función de prototipos?

+4

Necesitará la declaración directa cuando dos funciones se llamen entre sí. – kennytm

+1

posible duplicado de [¿Se necesitan prototipos para todas las funciones en C89, C90 o C99?] (Http://stackoverflow.com/questions/434763/are-prototypes-required-for-all-functions-in-c89-c90- or-c99) –

+1

No veo por qué. No estoy preguntando si son necesarios, simplemente no entiendo por qué están en el estándar en primer lugar. – Maulrus

Respuesta

3

En C prototipos se necesita para que su programa sabe que tiene una función llamada x() cuando no se ha llegado a definir que, de esa manera y() sabe que existe y existe una x(). C realiza una compilación descendente, por lo que debe definirse antes de que la mano sea la respuesta corta.

+1

Creo que esta respuesta se olvida por completo. Por un lado, puede llamar a cualquier función también sin un prototipo en el alcance y antes de que se defina (se aplican ciertas reglas). En segundo lugar, "compilación de arriba hacia abajo" (lo que sea que eso signifique exactamente) no es parte de C y no hay ningún requisito para compilar C de alguna manera específica. – Jens

+0

¡Tercero, su código cortado ni siquiera contiene los prototipos apropiados! Es muy descuidado, 'gcc -Wall -pedantic -std = c89 x.c' produce 10 advertencias. – Jens

0

Le permite tener una situación en la que decir que puede tener una clase de iterador definida en un archivo .h separado que incluye la clase contenedor primaria. Como ha incluido el encabezado padre en el iterador, no puede tener un método como por ejemplo "getIterator()" porque el tipo de retorno debería ser la clase de iterador y, por lo tanto, requeriría que incluya el encabezado del iterador dentro del el encabezado padre crea un bucle cíclico de inclusiones (una incluye la otra que se incluye a sí misma que incluye la otra de nuevo, etc.).

Si coloca el prototipo de clase de iterador dentro del contenedor primario, puede tener dicho método sin incluir el encabezado de iterador. Solo funciona porque simplemente dices que ese objeto existe y se definirá.

Hay formas de evitarlo como tener un encabezado precompilado, pero en mi opinión es menos elegante y viene con una serie de desventajas. De Couurse, esto es C++, no C. Sin embargo, en la práctica es posible que tenga una situación en la que le gustaría organizar el código de esta manera, dejando de lado las clases.

+0

¿Una clase de iterador, en C? La pregunta menciona C++, pero se trata de C razonamientos, por lo que creo que se necesita un ejemplo diferente :-) –

1

Tenía la impresión de que los clientes podían tener acceso al archivo .h para bibliotecas y ver qué funciones tenían disponibles, sin tener que ver la implementación (que estaría en otro archivo).

Útil para ver qué devuelve la función/qué parámetros.

+1

Obtener funciones disponibles de los encabezados es una mala idea porque los encabezados pueden contener magia arbitraria que no está disponible para el programador de la aplicación. Un desarrollador serio obtendrá toda la información que necesita de la documentación provista con las bibliotecas. Para el estándar C, POSIX y muchos más (incluso las API de Windows), la documentación está disponible gratuitamente y posiblemente ya esté allí (páginas man, ayuda de Windows, ...). Si necesita obtener un prototipo de un encabezado, se encuentra en el camino equivocado. – Jens

1

El prototipado de funciones es un remanente de los viejos tiempos de la escritura del compilador. Solía ​​considerarse terriblemente ineficiente para un compilador tener que hacer múltiples pasadas sobre un archivo fuente para compilarlo.

En C, en ciertos contextos, referirse a una función de una manera es sintácticamente equivalente a referirse a una variable: considere tomar un puntero a una función versus tomar un puntero a una variable. En la representación intermedia del compilador, los dos son semánticamente distintos, pero desde el punto de vista sintáctico, si un identificador es una variable, un nombre de función o un identificador no válido no se puede determinar a partir del contexto.

Como no es determinable desde el contexto, sin prototipos de funciones, el compilador tendría que pasar un pase extra sobre cada uno de sus archivos de origen cada vez que compila uno. Esto agregaría un factor O (n) adicional para cualquier compilación (es decir, si la compilación fuera O (m), ahora sería O (m * n)), donde n es el número de archivos en su proyecto. En proyectos grandes, donde la compilación ya está en el orden de las horas, tener un compilador de dos pasos es altamente indeseable.

Reenviar declarando todas sus funciones permitiría al compilador crear una tabla de funciones mientras escaneaba el archivo, y poder determinar cuándo encontró un identificador si se refería a una función o una variable.

Como resultado de esto, los compiladores C (y por extensión, C++) pueden ser extremadamente eficientes en la compilación.

+0

Eso no es necesariamente cierto: si no necesitaran prototipos de funciones, no tendrían que volver a analizar el mismo #include treinta veces. Es por eso que los encabezados precompilados son tan efectivos para reducir los tiempos de compilación en MSVC, porque # lleva tanto tiempo. – Puppy

+3

Me gusta el comienzo. Sí, el modelo de compilación es el culpable. Pero me gusta mucho menos la defensa de este modelo. Sugerencia de que los compiladores de C++ pueden ser extremadamente eficientes en la compilación, al final es un desastre. ¡Venga! –

11

El prototipado de funciones originalmente no se incluyó en C. Cuando llamó a una función, el compilador tomó su palabra que existiría y tomó el tipo de argumentos que proporcionó. Si obtuviste el orden, el número o el tipo incorrectos, es una lástima: tu código fallaría, posiblemente de manera misteriosa, en el tiempo de ejecución.

Versiones posteriores de prototipos de funciones C añadidas para solucionar estos problemas. Sus argumentos se convierten implícitamente a los tipos declarados en algunas circunstancias o se marcan como incompatibles con el prototipo, y el compilador puede marcar como error el orden incorrecto y la cantidad de tipos. Esto tuvo el efecto secundario de habilitar las funciones varargs y el manejo especial de los argumentos que requieren.

Tenga en cuenta que, en C (y al contrario que en C++), una función declarada foo_t func() es no lo mismo que una función declarada como foo_t func(void). Este último está prototipo para no tener argumentos. El primero declara una función sin un prototipo.

+0

+1 para la última sección sobre la diferencia entre una declaración y un prototipo. – legends2k