la déclaration de fonction n'est pas un prototype


158

J'ai une bibliothèque que j'ai créée,

mylib.c:

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

mylib.h:

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

Dans mon programme, j'ai tenté d'appeler cette fonction de bibliothèque:

monprogramme.c:

#include <mylib.h>

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

Lorsque j'essaye de compiler ce programme, j'obtiens l'erreur suivante:

Dans le fichier inclus de myprogram.c: 1
mylib.h: 2 avertissement: la déclaration de fonction n'est pas un prototype

J'utilise: gcc (GCC) 3.4.5 20051201 (Red Hat 3.4.5-2)

Ma question est la suivante: quelle est la bonne façon de déclarer un prototype de fonction?


1
Supprimez extern de la déclaration dans mylib.h Surtout si vous écrivez un programme C pur, la déclaration extern n'y est pas nécessaire.
Ryan Ahearn le

Réponses:


333

En C int foo()et int foo(void)sont des fonctions différentes. int foo()accepte un nombre arbitraire d'arguments, tandis int foo(void)qu'accepte 0 argument. En C ++, ils signifient la même chose. Je suggère que vous utilisiez voidsystématiquement lorsque vous ne parlez d'aucun argument.

Si vous avez une variable a, extern int a;est un moyen d'indiquer au compilateur que ac'est un symbole qui pourrait être présent dans une unité de traduction différente (le compilateur C parle pour le fichier source), ne le résolvez pas avant le moment de la liaison. Par contre, les symboles qui sont des noms de fonctions sont de toute façon résolus au moment de la liaison. La signification d'un spécificateur de classe de stockage sur une fonction ( extern, static) n'affecte que sa visibilité et externest la valeur par défaut, elle externn'est donc en fait pas nécessaire.

Je suggère de supprimer le extern, il est étranger et est généralement omis.


9
Utilisez (void) en C pour indiquer qu'une fonction ne prend aucun argument. En C ++, à moins que vous n'ayez spécifiquement besoin de votre code pour compiler à la fois en C et en C ++, utilisez simplement ().
Keith Thompson

49

Réponse rapide: remplacez int testlib()par int testlib(void)pour spécifier que la fonction ne prend aucun argument.

Un prototype est par définition une déclaration de fonction qui spécifie le (s) type (s) du ou des arguments de la fonction.

Une déclaration de fonction non-prototype comme

int foo();

est une déclaration à l'ancienne qui ne spécifie pas le nombre ou les types d'arguments. (Avant la norme ANSI C de 1989, c'était le seul type de déclaration de fonction disponible dans le langage.) Vous pouvez appeler une telle fonction avec n'importe quel nombre arbitraire d'arguments, et le compilateur n'est pas obligé de se plaindre - mais si le l'appel est incompatible avec la définition , votre programme a un comportement indéfini.

Pour une fonction qui prend un ou plusieurs arguments, vous pouvez spécifier le type de chaque argument dans la déclaration:

int bar(int x, double y);

Les fonctions sans argument sont un cas particulier. Logiquement, des parenthèses vides auraient été un bon moyen de spécifier qu'un argument mais cette syntaxe était déjà utilisé pour les déclarations de fonctions à l'ancienne, le comité ANSI C a donc inventé une nouvelle syntaxe en utilisant le voidmot - clé:

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

Une définition de fonction (qui comprend le code de ce que fait réellement la fonction) fournit également une déclaration . Dans votre cas, vous avez quelque chose de similaire à:

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

Cela fournit une déclaration non-prototype pour testlib. En tant que définition, cela indique au compilateur qui testlibn'a pas de paramètres, mais en tant que déclaration, il indique uniquement au compilateur qui testlibprend un certain nombre et type (s) d'arguments non spécifiés mais fixes.

Si vous passez ()à (void)la déclaration devient un prototype.

L'avantage d'un prototype est que si vous appelez accidentellement testlibavec un ou plusieurs arguments, le compilateur diagnostiquera l'erreur.

(C ++ a des règles légèrement différentes. C ++ n'a pas de déclarations de fonction à l'ancienne, et les parenthèses vides signifient spécifiquement qu'une fonction ne prend aucun argument. C ++ prend en charge la (void)syntaxe pour la cohérence avec C. Mais à moins que vous n'ayez spécifiquement besoin de votre code pour compiler les deux comme C et en C ++, vous devriez probablement utiliser le ()en C ++ et la (void)syntaxe en C.)


En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.