la dichiarazione di funzione non è un prototipo


158

Ho una biblioteca che ho creato,

mylib.c:

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

mylib.h:

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

Nel mio programma, ho provato a chiamare questa funzione di libreria:

myprogram.c:

#include <mylib.h>

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

Quando provo a compilare questo programma ottengo il seguente errore:

Nel file incluso da myprogram.c: 1
mylib.h: 2 avvertenza: la dichiarazione di funzione non è un prototipo

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

La mia domanda è: qual è il modo corretto di dichiarare un prototipo di funzione?


1
Rimuovi extern dalla dichiarazione in mylib.h Soprattutto se stai scrivendo un programma C puro, la dichiarazione extern non è necessaria lì.
Ryan Ahearn,

Risposte:


333

In C int foo()e int foo(void)sono diverse funzioni. int foo()accetta un numero arbitrario di argomenti, mentre int foo(void)accetta 0 argomenti. In C ++ significano la stessa cosa. Ti suggerisco di usare voidcoerentemente quando non intendi argomenti.

Se hai una variabile a, extern int a;è un modo per dire al compilatore che aè un simbolo che potrebbe essere presente in una diversa unità di traduzione (il compilatore C parla per il file sorgente), non risolverlo fino al momento del collegamento. D'altra parte, i simboli che sono nomi di funzioni vengono comunque risolti al momento del collegamento. Il significato di un identificatore della classe di archiviazione su una funzione ( extern, static) influisce solo sulla sua visibilità ed externè il valore predefinito, quindi in externrealtà non è necessario.

Suggerisco di rimuoverlo extern, è estraneo e di solito viene omesso.


9
Usare (void) in C per indicare che una funzione non accetta argomenti. In C ++, a meno che non sia specificamente necessario il codice per compilare sia come C sia come C ++, basta usare ().
Keith Thompson,

49

Risposta rapida: passare int testlib()a int testlib(void)per specificare che la funzione non accetta argomenti.

Un prototipo è per definizione una dichiarazione di funzione che specifica il tipo (i) degli argomenti della funzione.

Una dichiarazione di funzione non prototipo come

int foo();

è una dichiarazione vecchio stile che non specifica il numero o il tipo di argomenti. (Prima dello standard ANSI C del 1989, questo era l'unico tipo di dichiarazione di funzione disponibile nella lingua.) È possibile chiamare tale funzione con qualsiasi numero arbitrario di argomenti e il compilatore non è tenuto a lamentarsi, ma se il la chiamata non è coerente con la definizione , il programma ha un comportamento indefinito.

Per una funzione che accetta uno o più argomenti, è possibile specificare il tipo di ciascun argomento nella dichiarazione:

int bar(int x, double y);

Le funzioni senza argomenti sono un caso speciale. Logicamente, le parentesi vuote sarebbero state un buon modo per specificare che un argomento, ma che la sintassi era già in uso per dichiarazioni di funzioni vecchio stile, quindi il comitato ANSI C ha inventato una nuova sintassi usando la voidparola chiave:

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

Una definizione di funzione (che include il codice per ciò che fa effettivamente la funzione) fornisce anche una dichiarazione . Nel tuo caso, hai qualcosa di simile a:

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

Questo fornisce una dichiarazione non prototipo per testlib. Come definizione, questo dice al compilatore che testlibnon ha parametri, ma come una dichiarazione, dice solo al compilatore che testlibaccetta alcuni numeri e tipi di argomenti non specificati ma fissi.

Se si ()passa (void)alla dichiarazione diventa un prototipo.

Il vantaggio di un prototipo è che se si chiama accidentalmente testlibuno o più argomenti, il compilatore diagnostica l'errore.

(C ++ ha regole leggermente diverse. C ++ non ha dichiarazioni di funzioni vecchio stile e le parentesi vuote significano specificamente che una funzione non accetta argomenti. C ++ supporta la (void)sintassi per coerenza con C. Ma a meno che non sia necessario il proprio codice per compilare entrambi come C e come C ++, probabilmente dovresti usare ()in C ++ e la (void)sintassi in C.)


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.