TL;DR
Dans les déclarations,
void func1(); // obsolescent
void func2(void);
le comportement est tout à fait différent. La première déclare une fonction sans prototype - et elle peut prendre n'importe quel nombre d'arguments ! Alors que la seconde déclare une fonction avec un prototype, qui n'a pas de paramètres et n'accepte aucun argument.
Sur définitions
void func1() { } // obsolescent
et
void func2(void) { }
Ces deux éléments se comportent de manière distincte en ce sens que, alors que le compilateur C doit afficher un message de diagnostic lors de l'appel d'une fonction prototypée avec un nombre d'arguments erroné. n'a pas besoin le faire lors de l'appel d'une fonction sans prototype.
C'est-à-dire que, compte tenu des définitions ci-dessus
func1(1, 2, 3); // need not produce a diagnostic message
func2(1, 2, 3); // must always produce a diagnostic message
// as it is a constraint violation
Cependant les deux sont illégaux dans les programmes strictement conformes, car il s'agit d'un comportement explicitement indéfini, conformément à la règle suivante 6.5.2.2p6 .
En outre, les parenthèses vides sont considérées comme une fonctionnalité obsolète :
L'utilisation de déclarateurs de fonctions avec des parenthèses vides (et non de déclarateurs de types de paramètres sous forme de prototypes) est une fonctionnalité obsolète.
et
L'utilisation de définitions de fonctions avec des listes séparées d'identifiants et de déclarations de paramètres (et non des déclarateurs de types et d'identifiants de paramètres au format prototype) est une fonctionnalité obsolète.
En détail
Il existe deux concepts connexes, mais distincts : les paramètres et les arguments.
Dans l'extrait suivant :
int foo(int n, char c) {
...
}
...
foo(42, ch);
n
et c
sont des paramètres. 42
et ch
sont des arguments.
L'extrait cité ne concerne que les paramètres d'une fonction, mais ne mentionne rien sur le prototype ou les arguments de la fonction.
Le site déclaration void func1()
signifie que la fonction func1
peut être appelé avec un nombre quelconque de arguments c'est-à-dire qu'aucune information sur le nombre d'arguments n'est spécifiée (en tant que déclaration séparée, C99 spécifie ceci comme "fonction sans spécification de paramètre"), alors que la déclaration void func2(void)
signifie que la fonction func2
n'accepte pas de arguments du tout.
Le guillemet dans votre question signifie que dans un définition des fonctions , void func1()
et void func2(void)
les deux signalent qu'il n'y a pas paramètres c'est-à-dire des noms de variables qui sont définis par les valeurs des arguments lorsque la fonction est saisie. Le site void func() {}
s'oppose à void func();
le premier déclare que func
ne prend en effet aucun paramètre, alors que cette dernière est une déclaration pour une fonction func
pour laquelle ni paramètres ni leurs types sont spécifiés (une déclaration sans prototype).
Cependant, ils diffèrent encore sur le plan de la définition en ce sens que
-
La définition void func1() {}
ne déclare pas de prototype, alors que void func2(void) {}
le fait, car ()
n'est pas une liste de types de paramètres, alors que (void)
est une liste de types de paramètres ( 6.7.5.3.10 ) :
Le cas particulier d'un paramètre non nommé de type void comme seul élément de la liste indique que la fonction n'a pas de paramètres.
et en outre 6.9.1.7
Si le déclarateur inclut une liste de types de paramètres, la liste spécifie également les types de tous les paramètres par défaut. spécifie également les types de tous les paramètres ; un tel déclarateur sert également de prototype de fonction pour les appels ultérieurs à la même fonction dans la même unité de traduction. Si le déclarateur comprend une liste d'identifiants, les types des paramètres sont déclarés dans une liste de déclaration suivante. Dans les deux cas, le type de chaque paramètre est ajusté comme décrit au point 6.7.5.3 pour une liste de types de paramètres ; le type résultant doit être un type d'objet.
Le déclarateur de la définition de fonction pour func1
fait pas contiennent un liste des types de paramètres et donc la fonction n'a pas de prototype.
-
void func1() { ... }
peut toujours être appelé avec un nombre quelconque d'arguments, alors que c'est une erreur de compilation d'appeler void func2(void) { ... }
avec des arguments quelconques (6.5.2.2) :
Si l'expression qui désigne la fonction appelée a un type qui comprend un prototype le nombre d'arguments doit correspondre au nombre de paramètres. Chaque argument doit avoir un type tel que sa valeur puisse être attribuée à un objet ayant la version non qualifiée du type de son paramètre correspondant.
(c'est moi qui souligne)
Il s'agit d'un contrainte qui, selon la norme, indique qu'une implémentation conforme doit afficher au moins un message de diagnostic sur ce problème. Mais comme func1
n'a pas de prototype, une implémentation conforme n'est pas tenue de produire des diagnostics.
Toutefois, si le nombre d'arguments n'est pas égal au nombre de paramètres, la fonction le comportement est indéfini 6.5.2.2p6 :
Si l'expression qui dénote la fonction appelée a un type qui n'est pas ne pas inclure de prototype , [...] Si le nombre d'arguments n'est pas égal au nombre de paramètres, le comportement est indéfini.
Donc, en théorie, un compilateur C99 conforme est également autorisé à commettre une erreur ou à diagnostiquer un avertissement dans ce cas. StoryTeller a fourni des preuves que clang pourrait diagnostiquer ceci Cependant, mon GCC ne semble pas le faire (et cela pourrait aussi être nécessaire pour qu'il soit compatible avec certains vieux codes obscurs) :
void test() { }
void test2(void) { }
int main(void) {
test(1, 2);
test2(1, 2);
}
Lorsque le programme ci-dessus est compilé avec gcc -std=c99 test.c -Wall -Werror
le résultat est :
test.c: In function ‘main’:
test.c:7:5: error: too many arguments to function ‘test2’
test2(1, 2);
^~~~~
test.c:3:6: note: declared here
void test2(void) { }
^~~~~
C'est-à-dire que les arguments ne sont pas du tout vérifiés par rapport aux paramètres d'une fonction dont la déclaration en définition n'est pas prototypée ( test
) alors que GCC considère comme une erreur de compilation le fait de spécifier des arguments à une fonction prototypée ( test2
) ; toute mise en œuvre conforme doit diagnostiquer cela car il s'agit d'une violation de contrainte.