est f (void) obsolète en C et C ++ modernes [duplicate]
-
03-07-2019 - |
Question
Cette question a déjà une réponse ici:
Je suis actuellement en train de refactoriser / nettoyer un ancien code C utilisé dans un projet C ++ et je vois régulièrement des fonctions telles que:
int f(void)
que j'aurais tendance à écrire comme:
int f()
Y at-il une raison de ne pas remplacer (void) par () dans l’ensemble de la base de code afin d’améliorer la cohérence ou existe-t-il une différence subtile entre les deux que je ne connais pas? Plus précisément, si une fonction membre virtuelle en C ++ est décrite comme suit:
virtual int f(void)
et une classe dérivée inclut une fonction membre:
<*>est-ce une substitution valide? De plus, suis-je susceptible de rencontrer des problèmes d’éditeur de liens basés sur des signatures presque identiques?
La solution
En C, la déclaration int f (void)
désigne une fonction renvoyant int qui ne prend aucun paramètre. La déclaration int f ()
désigne une fonction renvoyant int qui prend un nombre quelconque de paramètres. Ainsi, si vous avez une fonction qui ne prend aucun paramètre en C, le premier est le bon prototype.
En C ++, je pense que int f (void)
est obsolète et que int f ()
est préféré, car il s'agit spécifiquement d'une fonction qui ne prend aucun paramètre.
Autres conseils
Pour ajouter à la réponse de Chris, utiliser int f ()
est une mauvaise pratique en C, selon mon expérience, car vous perdez la capacité du compilateur à comparer la déclaration de la fonction à sa définition, pour s'assurer qu'elle sera appelé correctement.
Par exemple, le code suivant est conforme aux normes C:
#include <stdio.h>
void foo();
void bar(void) {
foo();
}
void foo(int a) {
printf("%d\n", a);
}
Mais il en résulte un comportement non défini, car un
n'a pas été transmis à toto
.
En C ++, il existe deux versions de foo
: une qui ne prend aucun argument et une qui prend un int
. Ainsi, bar
appelle la version indéfinie, ce qui entraînerait une erreur de l'éditeur de liens (en supposant qu'il n'y ait pas d'autres définitions de foo
nulle part).
Les réponses ci-dessus sont tout à fait correctes, mais je vous renvoie à l'excellente page de David Tribble car elle donne un bonne explication sur ce sujet et sur de nombreux autres.
Les points forts:
C distingue une fonction déclaré avec une liste de paramètres vide et une fonction déclarée avec un liste de paramètres composée de vide. Le premier est un non-prototype fonction prenant un nombre non spécifié d'arguments, alors que ce dernier est un fonction prototypée ne prenant pas arguments.
C ++, en revanche, ne fait pas distinction entre les deux déclarations et les considère à la fois signifier une fonction ne prenant pas arguments.
Pour le code destiné à être compilé en C ou C ++, le meilleur la solution à ce problème est de toujours déclarer des fonctions ne prenant aucun paramètre avec un prototype de vide explicite.
Les prototypes de fonctions vides sont un fonction obsolète en C99 (car ils étaient en C89).
Éditer: Après avoir examiné la norme, il convient peut-être de noter que la syntaxe func (void) n'est pas déconseillée en C ++, mais elle est généralement considérée comme un idiome de style C. Je pense que la plupart des programmeurs C ++ que j'ai rencontrés préfèrent la liste de paramètres vide.
Édition 2: Ajout d'une citation de la norme C ++, section 8.3.5, paragraphe 2:
" Si la clause de déclaration de paramètre est vide, la fonction ne prend aucun argument. La liste de paramètres (void) équivaut à la liste de paramètres vide. Sauf dans ce cas particulier, void ne doit pas être un type de paramètre (bien que les types dérivés de void, tels que void *, puissent). "
Rien n’indique que l’un ou l’autre des formulaires est obsolète. Merci encore à l'excellent site Web de M. Tribble pour m'avoir signalé la bonne section de la norme.
tl; dr: utilisez void
.
Étant donné la compatibilité ascendante en C ++ et le peu d’ambiguïté identifiée ci-dessous, j’affirme que nous remontons à KnR et à ANSI C pour une réponse concluante:
int getline(void);
int copy(void)
Comme les versions spécialisées de getline et copy n'ont pas d'argument, la logique suggérerait que leurs prototypes au début du fichier doit être
getline ()
etcopy ()
. Mais pour la compatibilité avec programmes C plus anciens, la norme prend une liste vide comme à l’ancienne déclaration et désactive toutes les vérifications de la liste d’arguments; le motvoid
doit être utilisé pour une liste explicitement vide. [Kernighan & amp; Richie, langage de programmation C, 1988, pages 32 à 33]
et ..
La signification particulière de la liste des arguments vides est destinée à permettre programmes C plus anciens à compiler avec de nouveaux compilateurs. Mais c'est une mauvaise idée de utilisez-le avec de nouveaux programmes. Si la fonction prend des arguments, déclare leur; si cela ne prend aucun argument, utilisez void [ibid, p. 73]
EDIT: Divisé le reste en une discussion séparée ici: La spécification de l’utilisation de void dans la déclaration d’une fonction ne prenant pas d’argument adresse-t-elle l’analyse la plus frustrante?
void f ()
est obsolète, void f (void)
recommandé:
6.11.6 Déclarateurs de fonction :
1 Utilisation de déclarateurs de fonction avec des parenthèses vides (paramètre non au format prototype déclarateurs de type) est une fonctionnalité obsolète.
Introduction :
2 Certaines fonctionnalités sont obsolètes, ce qui signifie qu'elles peuvent être considérées retrait lors de futures révisions de la présente Norme internationale. Ils sont retenus car leur utilisation répandue, mais leur utilisation dans les nouvelles implémentations (pour fonctions) ou de nouveaux programmes (pour la langue [6.11] ou les fonctions de bibliothèque [7.31]) est déconseillée.
Discussion détaillée: https://stackoverflow.com/a/36292431/895245
Ni void f (void)
ni void f ()
ne sont déconseillés.
void f (void)
existe pour une compatibilité avec C. Annexe C "Compatibilité" C.1.7 Article 8: déclarateurs :
8.3.5 Modification: En C ++, une fonction déclarée avec une liste de paramètres vide ne prend aucun argument. En C, un vide liste de paramètres signifie que le nombre et le type des arguments de la fonction sont inconnus.
Puisque void f ()
est obsolète en C et que void f (void)
est recommandé, void f (void)
existera pour tant que C ++ veut maintenir la compatibilité.
void f (void)
et void f ()
sont identiques en C ++. Ainsi, void f (void)
plus long n'a de sens que si vous vous souciez d'écrire du code compilé à la fois en C et en C ++, ce qui n'en vaut probablement pas la peine.
Discussion détaillée: https://stackoverflow.com/a/36835303/895245
En C ++, int f (void)
est en effet une déclaration dépréciée équivalente à 100% à int f ()
. c'est la même signature. Le void
dans ce contexte est aussi important que par exemple. les espaces blancs Cela signifie également qu'ils sont soumis à la règle de définition unique (ils ne surchargent pas) et Derived :: f (void)
remplace Base :: f ()
.
Ne jouez pas avec des choses comme f (const void)
, cependant. Il n'y a pas beaucoup de consensus sur ce genre de bizarreries.