Pourquoi une fonction sans paramètres (par rapport à la définition d'une fonction réelle) de la compilation?
je viens de trouver le code C de quelqu'un que je ne comprends pas. Il y a deux points que je ne comprends pas.
tout d'abord, le prototype de fonction n'a aucun paramètre comparé à la définition de fonction réelle. Deuxièmement, le paramètre dans la définition de la fonction n'a pas de type.
#include <stdio.h>
int func();
int func(param)
{
return param;
}
int main()
{
int bla = func(10);
printf("%d", bla);
}
pourquoi ça marche? Je l'ai testé dans quelques Compilateurs, et ça marche très bien.
11 réponses
Toutes les autres réponses sont correctes, mais juste pour achèvement
Une fonction est déclarée de la manière suivante:
return-type function-name(parameter-list,...) { body... }
retour de type est le type de variable que la fonction renvoie. Cela ne peut pas être un type tableau ou un type de fonction. Si pas donné, alors int est supposé .
fonction-Nom est le nom de la fonction.
paramètre-liste est la liste des paramètres que la fonction prend séparés par des virgules. Si aucun paramètre n'est donné, alors la fonction ne prend pas et doit être défini avec un ensemble vide de entre parenthèses ou avec le mot-clé nul. Si Aucune variable type est en tête d'une variable dans la liste paramater, alors int est supposé . Les tableaux et les les fonctions ne sont pas passées aux fonctions, mais sont automatiquement converties pour les pointeurs. Si la liste se termine par une ellipse (,...), puis il n'y a pas de nombre fixe de paramètres. Remarque: l'en-tête stdarg.h peut être utilisé pour accéder aux arguments lors de l'utilisation d'une ellipse.
et encore pour être complet. De l'C11 spécification 6:11:6 (page: 179)
Le utilisation de la fonction déclarants avec des parenthèses vides (Non prototype-format type de paramètre declarators) est la vétusté des la fonctionnalité .
C func()
signifie que vous pouvez passer n'importe quel nombre d'arguments. Si vous ne voulez pas d'arguments, alors vous devez déclarer que func(void)
. Le type que vous passez à votre fonction, s'il n'est pas spécifié par défaut à int
.
int func();
est une déclaration de fonction obsolescente des jours où il n'y avait pas de norme C, c.-à-d. les jours de K&R C (avant 1989, l'année où la première Norme "ANSI C" a été publiée).
rappelez-vous qu'il n'y avait aucun prototype dans K&R C et le mot-clé void
n'a pas encore été inventé. Tout ce que vous pouviez faire était de dire au compilateur le type de retour d'une fonction. Le vide liste des paramètres dans K & R C signifie "un nombre non spécifié mais fixe" d'arguments. Fixe signifie que vous devez appeler la fonction avec le même nombre d'args à chaque fois (par opposition à un variadique fonction comme printf
, où le nombre et le type peuvent varier pour chaque appel).
beaucoup de compilateurs vont diagnostiquer cette construction; en particulier gcc -Wstrict-prototypes
va vous dire "déclaration de fonction n'est pas un prototype", qui est spot sur, parce que ressemble à comme un prototype (surtout si vous êtes empoisonné par C++!), but isn'T. C'est une ancienne déclaration de type K & R C.
règle empirique: ne laissez jamais vide une déclaration de liste de paramètres, utilisez int func(void)
pour être précis.
Cela fait de la déclaration de type de retour K&R un prototype C89 adéquat. Les compilateurs sont heureux, les développeurs sont heureux, statique pions sont heureux. Ceux qui sont induits en erreur par un tiers de c++ peut grincer, cependant, parce qu'ils ont besoin de taper des caractères supplémentaires quand ils essaient d'exercer leurs compétences en langues étrangères: -)
- la liste des paramètres vide signifie "Tous les arguments", donc la définition n'est pas erronée.
- le type manquant est supposé être
int
.
je considérerais toute construction qui dépasse ce niveau comme manquant dans le niveau d'avertissement/d'erreur configuré, cependant, il n'y a aucun intérêt à être cela permettant le code réel.
Il est K&R style déclaration de la fonction et de la définition. De la norme C99 (ISO / IEC 9899: TC3)
Section 6.7.5.3 Declarateurs de fonctions (y compris prototypes)
une liste d'identificateurs ne déclare que les identificateurs des paramètres de la fonction. Un vide liste dans une fonction de demande de déclaration qui fait partie d'une définition de cette fonction spécifie que le la fonction n'a pas de paramètres. le liste vide dans un déclarant de fonction qui ne fait pas partie d'un la définition de cette fonction précise qu'aucune information sur le nombre ou les types de paramètres est fournie. (Si les deux types de fonctions sont "ancien style", les types de paramètres ne sont pas comparés.)
Section 6.11.6 fonction declarateurs
l'utilisation de La fonction declarators avec des parenthèses vides (pas de prototype-paramètre de format de type declarators) est un dispositif obsolescent .
Section 6.11.7 fonctions définitions
l'utilisation de définitions de fonctions avec des listes séparées d'Identificateur de paramètre et de déclaration (pas de prototype-paramètre de format de type et l'identifiant de declarators) est un de caducité de fonctionnalité.
que l'ancien style signifie K&R style
exemple:
déclaration: int old_style();
définition:
int old_style(a, b)
int a;
int b;
{
/* something to do */
}
c suppose int
si aucun type n'est indiqué sur le type de retour de fonction et la liste des paramètres . Seulement pour cette règle suivant des choses bizarres sont possibles.
une définition de fonction ressemble à ceci.
int func(int param) { /* body */}
si c'est un prototype vous écrivez
int func(int param);
dans prototype, vous ne pouvez spécifier que le type de paramètres. Paramètres nom n'est pas obligatoire. So
int func(int);
aussi si vous ne spécifiez pas le type de paramètre mais le nom int
est supposé comme type.
int func(param);
si vous allez plus loin, suivez les travaux aussi.
func();
compilateur suppose int func()
quand vous écrivez func()
. Mais ne mettez pas func()
dans un corps fonctionnel. Ce sera une fonction appelée
comme l'a déclaré @Krishnabhadra, toutes les réponses précédentes d'autres utilisateurs, ont une interprétation correcte, et je veux juste faire une analyse plus détaillée de certains points.
dans L'ancien-C comme dans L'ANSI-C le " paramètre formel non typé ", prendre la dimension de votre capacité de profondeur de registre de travail ou d'instruction (registres d'ombre ou cycle cumulatif d'instruction), dans un MPU 8bit, sera un int16, dans un MPU 16bit et sera donc un int16 un So, dans ce cas, les architectures 64bit peuvent choisir de compiler des options comme: -m32.
bien qu'il semble plus simple de mettre en œuvre à un niveau élevé, Pour passer des paramètres multiples, le travail du programmeur dans l'étape de contrôle de type de données dimensionnelles, devient plus exigeant.
dans d'autres cas, pour certaines architectures de microprocesseurs, les compilateurs ANSI personnalisés, ont tiré parti de certaines de ces anciennes fonctionnalités pour optimiser l'utilisation du code, forçant l'emplacement de ces "paramètres formels non typés" pour travailler à l'intérieur ou à l'extérieur du registre de travail, aujourd'hui vous obtenez presque le même avec l'utilisation de "volatile" et "Registre".
mais il convient de noter que les compilateurs les plus modernes, ne pas faire de distinction entre les deux types de paramètres de déclaration.
exemples d'une compilation avec gcc sous linux:
dans tous les cas la déclaration du prototype localement n'est d'aucune utilité, parce qu'il n'y a pas d'appel sans paramètres référence à ce prototype sera négligent.
Si vous utilisez le système avec "untyped formal parameter", pour un appel externe, procédez à générer un type de données prototype déclaratif.
comme ceci:
int myfunc(int param);
en ce qui concerne le type de paramètre, il y a déjà des réponses correctes ici, mais si vous voulez l'entendre du compilateur vous pouvez essayer d'ajouter quelques drapeaux (les drapeaux sont presque toujours une bonne idée de toute façon).
compiler votre programme en utilisant gcc foo.c -Wextra
I get:
foo.c: In function ‘func’:
foo.c:5:5: warning: type of ‘param’ defaults to ‘int’ [-Wmissing-parameter-type]
étrangement -Wextra
ne comprend pas ce pour clang
(il ne reconnaît pas -Wmissing-parameter-type
pour une raison quelconque, peut-être pour les historiques mentionnés ci-dessus) mais -pedantic
does:
foo.c:5:10: warning: parameter 'param' was not declared,
defaulting to type 'int' [-pedantic]
int func(param)
^
1 warning generated.
et pour la sortie du prototype comme dit plus haut int func()
se réfère à des paramètres arbitraires à moins que vous ne le définissiez explicitement comme int func(void)
qui vous donnerait alors les erreurs comme prévu:
foo.c: In function ‘func’:
foo.c:6:1: error: number of arguments doesn’t match prototype
foo.c:3:5: error: prototype declaration
foo.c: In function ‘main’:
foo.c:12:5: error: too many arguments to function ‘func’
foo.c:5:5: note: declared here
ou dans clang
comme:
foo.c:5:5: error: conflicting types for 'func'
int func(param)
^
foo.c:3:5: note: previous declaration is here
int func(void);
^
foo.c:12:20: error: too many arguments to function call, expected 0, have 1
int bla = func(10);
~~~~ ^~
foo.c:3:1: note: 'func' declared here
int func(void);
^
2 errors generated.
si la déclaration de fonction n'a pas de paramètres, c'est-à-dire vide, alors elle prend un nombre non spécifié d'arguments. Si vous voulez faire prendre aucun argument alors le modifier:
int func(void);
c'est pourquoi je conseille aux gens de compiler leur code avec:
cc -Wmissing-variable-declarations -Wstrict-variable-declarations -Wold-style-definition
ces drapeaux font respecter deux choses:
- - Wmissing-variable-déclarations: il est impossible de déclarer une fonction non statique sans avoir d'abord un prototype. Il est donc plus probable qu'un prototype dans un fichier d'en-tête corresponde à la définition réelle. Alternativement, il renforce que vous ajoutez le mot-clé statique à des fonctions qui ne doivent être visibles publiquement.
- -Wstrict-variable-declarations: le prototype doit correctement énumérer les arguments.
- -Wold-style-définition: la définition de la fonction elle-même doit également correctement énumérer les arguments.
ces options sont également utilisées par défaut dans de nombreux projets Open Source. Par exemple, FreeBSD a activé ces options lorsque vous construisez avec WARNS=6 dans votre Makefile.
Sir, en C++ ( et C++ seulement ) vous êtes autorisé à définir plusieurs fonctions du même nom avec des paramètres différents. Par exemple:
int func();
int func(int test);
int func(char testing123);
devrait être compilé. Pour choisir la fonction à utiliser, passez simplement ce type de variable dans la parenthèse lorsque vous compilez.
par exemple:
int testing123=2;
func(testing123);
appellera func(test int).
attendu que
char test='a';
func(test);
s'appellera func(char).
vous n'avez pas besoin de noms de variables dans l'en-tête de fonction, bien que tant que la fonction prototype (vous savez, la ligne en haut qui a juste une fonction sans code en elle) correspond aux noms dans la fonction réelle ci-dessous vous serez un bon (par exemple, au lieu de int func(int)
vous pourriez tout aussi bien avoir int func(int avariable).
quant à la variable dans le prototype compilant sans type, elle est probablement par défaut le type, probablement de type int (bien que je ne suis pas sûr si le type par défaut varie en fonction du compilateur ou pas.)