la declaración de función no es un prototipo

158

Tengo una biblioteca que creé,

mylib.c:

#include <mylib.h>
int
testlib() {
    printf("Hello world\n");
    return (0);
}

mylib.h:

#include <stdio.h>
extern int testlib();

En mi programa, intenté llamar a esta función de biblioteca:

myprogram.c:

#include <mylib.h>

int
main (int argc, char *argv[]) {
    testlib();
    return (0);
}

Cuando intento compilar este programa me sale el siguiente error:

En el archivo incluido desde myprogram.c: 1
mylib.h: 2 advertencia: la declaración de función no es un prototipo

Estoy usando: gcc (GCC) 3.4.5 20051201 (Red Hat 3.4.5-2)

Mi pregunta es, ¿cuál es la forma correcta de declarar un prototipo de función?

Alan H
fuente
1
Elimine extern de la declaración en mylib.h Especialmente si está escribiendo un programa C puro, la declaración extern es innecesaria allí.
Ryan Ahearn

Respuestas:

333

En C int foo()y int foo(void)son diferentes funciones. int foo()acepta un número arbitrario de argumentos, mientras que int foo(void)acepta 0 argumentos. En C ++ significan lo mismo. Le sugiero que use voidconsistentemente cuando no quiere decir argumentos.

Si tiene una variable a, extern int a;es una forma de decirle al compilador que aes un símbolo que podría estar presente en una unidad de traducción diferente (el compilador C habla por el archivo fuente), no lo resuelva hasta el momento del enlace. Por otro lado, los símbolos que son nombres de funciones se resuelven de todos modos en el momento del enlace. El significado de un especificador de clase de almacenamiento en una función ( extern, static) solo afecta su visibilidad y externes el valor predeterminado, por externlo que en realidad es innecesario.

Sugiero eliminar el extern, es extraño y generalmente se omite.

Pramod
fuente
9
Use (void) en C para indicar que una función no toma argumentos. En C ++, a menos que necesite específicamente su código para compilar tanto como C como C ++, simplemente use ().
Keith Thompson
49

Respuesta rápida: cambie int testlib()a int testlib(void)para especificar que la función no acepta argumentos.

Un prototipo es, por definición, una declaración de función que especifica el tipo (s) de los argumentos de la función.

Una declaración de función no prototipo como

int foo();

es una declaración de estilo antiguo que no especifica el número o los tipos de argumentos. (Antes del estándar ANSI C de 1989, este era el único tipo de declaración de función disponible en el lenguaje). Puede llamar a tal función con cualquier número arbitrario de argumentos, y el compilador no está obligado a quejarse, pero si el la llamada es inconsistente con la definición , su programa tiene un comportamiento indefinido.

Para una función que toma uno o más argumentos, puede especificar el tipo de cada argumento en la declaración:

int bar(int x, double y);

Las funciones sin argumentos son un caso especial. Lógicamente, los paréntesis vacíos habrían sido una buena forma de especificar que un argumento pero esa sintaxis ya estaba en uso para las declaraciones de funciones de estilo antiguo, por lo que el comité ANSI C inventó una nueva sintaxis usando la voidpalabra clave:

int foo(void); /* foo takes no arguments */

Una definición de función (que incluye código para lo que realmente hace la función) también proporciona una declaración . En su caso, tiene algo similar a:

int testlib()
{
    /* code that implements testlib */
}

Esto proporciona una declaración de no prototipo para testlib. Como definición, esto le dice al compilador que testlibno tiene parámetros, pero como una declaración, solo le dice al compilador que testlibtoma algunos números y tipos de argumentos no especificados pero fijos.

Si cambia ()a (void)la declaración se convierte en un prototipo.

La ventaja de un prototipo es que si llama accidentalmente testlibcon uno o más argumentos, el compilador diagnosticará el error.

(C ++ tiene reglas ligeramente diferentes. C ++ no tiene declaraciones de funciones de estilo antiguo, y los paréntesis vacíos significan específicamente que una función no tiene argumentos. C ++ admite la (void)sintaxis para mantener la coherencia con C. Pero a menos que necesite específicamente su código para compilar ambos como C y como C ++, probablemente debería usar ()en C ++ y la (void)sintaxis en C.)

Keith Thompson
fuente
22

Tratar:

extern int testlib(void);
Lasse V. Karlsen
fuente