De la “conflicting types de fonction” en C, pourquoi?
Je suis en utilisant le code ci-dessous:
char dest[5];
char src[5] = "test";
printf("String: %s\n", do_something(dest, src));
char *do_something(char *dest, const char *src)
{
return dest;
}
La mise en œuvre de do_something
n'est pas important ici.
Lorsque j'essaie de compiler le ci-dessus, je reçois ces deux exceptions:
erreur: conflicting types for 'faire_quelque_chose" (à l'printf appel)
erreur: la précédente déclaration implicite de "faire_quelque_chose' était ici (à la ligne prototype)
Pourquoi?
- J'ai été faire cette même erreur, mais je n'étais pas à l'appel de la fonction n'importe où, pourtant, ni avant, ni après sa définition), donc la réponse choisie n'était pas applicable dans mon cas. S'avère que le problème était dû à un conflit de noms - mon nom de la fonction, a été "mergesort" (je suis en train de suivre avec Skiena de "la Conception d'un Algorithme Manuel") et il y a déjà un nom identique fonction dans stdlib.h. Renommer ma fonction merge_sort" a fait le tour.
Vous devez vous connecter pour publier un commentaire.
Que vous essayez d'appeler faire_quelque_chose avant de vous déclarer. Vous avez besoin d'ajouter une fonction de prototype avant votre printf ligne:
Ou vous avez besoin de déplacer la définition de la fonction au-dessus de la ligne printf. Vous ne pouvez pas utiliser une fonction avant qu'il ne soit déclaré.
Dans le "classique" du langage C (C89/90) lorsque vous appelez un non déclarées fonction, C suppose qu'elle renvoie un
int
et tente de tirer les types de ses paramètres à partir des types des arguments réels (non, ce n'est pas supposer qu'il n'a pas de paramètres, comme quelqu'un l'a suggéré avant).Dans votre exemple, le compilateur aurait regardez
do_something(dest, src)
appel et, implicitement, de dériver une déclaration pourdo_something
. Ce dernier se présente comme suitCependant, plus tard dans le code, vous déclarez explicitement
do_something
commeComme vous pouvez le voir, ces déclarations sont différents les uns des autres. C'est ce que le compilateur n'aime pas.
int foo()
pour faire fonctionnerfoo
officiellement déclarée. Dans C (contrairement à C++)()
dans la déclaration de fonction encore signifie que les paramètres de la fonction liste est non spécifié et doit être "déduit" par le compilateur exactement comme décrit ci-dessus. I. e. Les compilateurs C ne plus déduire la fonction des types de retour, mais des listes de paramètres peuvent encore être déduite.int (char *, char *)
tandis que le réel type de fonction estchar *(char *, const char *)
. Toutefois, la règle générale qui est violé dans ce cas s'applique à tous les types de déclarations (pas seulement "déduit", non seulement les déclarations de fonction). Par exemple, vous pouvez déclarerextern double a;
puis définirint a;
et vous obtiendrez la même erreur à propos contradictoires types. Et, apparemment, GCC auteurs ne pense pas que les fonctions qui méritent d'être traités séparément.Vous n'avez pas le déclarer avant de vous en servir.
Vous besoin de quelque chose comme
avant le printf.
Exemple:
Alternativement, vous pouvez mettre l'ensemble de
do_something
fonction avant le printf.Vous devez déclarer la fonction avant de l'utiliser. Si le nom de la fonction s'affiche avant sa déclaration, le compilateur C va suivre certaines règles et fait la déclaration elle-même. Si c'est faux, vous obtiendrez cette erreur.
Vous avez deux options: (1) définir avant de l'utiliser, ou (2) l'utilisation de l'avant déclaration sans la mise en œuvre. Par exemple:
Remarque le point-virgule à la fin.
Une Fonction C-Déclaration De Document D'Information
En C, les déclarations de fonction ne fonctionnent pas comme ils le font dans d'autres langues: Le compilateur C lui-même n'est pas une recherche en arrière et en avant dans le fichier pour trouver la déclaration de la fonction du lieu de l'appeler, et il n'a pas d'analyser le fichier plusieurs fois pour comprendre les relations, soit: Le compilateur ne scanne avant dans le fichier exactement une fois, de haut en bas. La connexion des appels de fonction pour les déclarations de fonction est une partie de l'éditeur de liens de travail, et se fait uniquement après le fichier est compilé vers le bas à raw instructions de montage.
Cela veut dire que le compilateur recherche avant par l'intermédiaire du fichier, la première fois que le compilateur rencontre le nom d'une fonction, de deux choses l'avez d'être le cas: Il en soit, c'est de voir la déclaration de la fonction elle-même, auquel cas le compilateur sait exactement ce que la fonction est, et quels types il prend comme arguments et quels types de retours — ou c'est un appel à la fonction, et que le compilateur doit deviner la façon dont la fonction sera finalement déclaré.
(Il y a une troisième option, où le nom est utilisé dans une fonction de prototype, mais nous allons ignorer que, pour l'instant, car si vous voyez ce problème en premier lieu, vous n'êtes probablement pas à l'aide de prototypes.)
Leçon D'Histoire
Dans les premiers jours de C, le fait que le compilateur a dû deviner les types n'était pas vraiment un problème: Tous les types ont été plus ou moins le même pratiquement tout ce qui était soit un int ou un pointeur, et qu'ils étaient de la même taille. (En fait, dans le cas B, la langue qui l'a précédé C, il n'y avait pas de types à tous; tout était juste un int ou un pointeur et son type a été déterminé uniquement par la façon dont on s'en sert!) Ainsi, le compilateur en toute sécurité de deviner le comportement de n'importe quelle fonction seulement en fonction du nombre de paramètres qui ont été transmises: Si vous avez passé les deux paramètres, le compilateur devrait pousser les deux choses sur la pile d'appel, et sans doute le destinataire de l'appel aurait deux arguments a déclaré, et ce serait de toute la ligne. Si vous avez passé un seul paramètre, mais la fonction attend deux, il serait tout de tri de travail, et le deuxième argument serait tout simplement être ignorée/ordures. Si vous avez passé les trois paramètres et la fonction attend deux, il serait également toujours en sorte de travail, et le troisième paramètre sera ignoré et piétiné par la fonction de variables locales. (Certains vieux code C encore que ces incompatibles-argument règles de travail, aussi.)
Mais ayant le compilateur vous laisser passer n'importe quoi à n'importe quoi n'est pas vraiment une bonne façon de concevoir un langage de programmation. Il a bien fonctionné dans les premiers jours parce que les premiers programmeurs C étaient pour la plupart des assistants, et ils ne savaient pas à passer le mauvais type de fonctions, et même si elles n'en obtenir le type de mal, il y avait toujours des outils comme
lint
qui pourrait faire plus de double vérification de votre code C et de vous avertir au sujet de telles choses.Avance rapide jusqu'à aujourd'hui, et nous ne sommes pas tout à fait dans le même bateau. C a grandi, et beaucoup de gens sont de programmation qui ne sont pas des magiciens, et de les accueillir (et pour accueillir tout le monde qui utilisent régulièrement
lint
de toute façon), les compilateurs ont pris de nombreuses compétences qui faisaient précédemment partie delint
— surtout la partie où ils vérifier votre code pour s'assurer qu'il est de type sécurisé. Début des compilateurs C permet d'écrireint foo = "hello";
et il serait juste allègrement affecter le pointeur vers un entier, et que c'était à vous de vous assurer que vous n'avez pas à faire quelque chose de stupide. Moderne compilateurs C se plaindre bruyamment quand vous obtenez vos types de mal, et c'est une bonne chose.Type De Conflits
Donc, ce que tout cela a à voir avec le mystérieux contradictoires-type de l'erreur sur la ligne de la déclaration de la fonction? Comme je l'ai dit ci-dessus, les compilateurs C encore soit savoir ou deviner quel nom désigne la première fois qu'ils voient ce nom comme ils le scan de l'avant par l'intermédiaire du fichier: Ils peuvent savoir ce que cela signifie si c'est une véritable déclaration de la fonction elle-même (ou une fonction de "prototype", plus loin), mais si c'est juste un appel à la fonction, ils doivent deviner. Et, malheureusement, l'estimation est souvent erroné.
Lorsque le compilateur vu votre appel à
do_something()
, il avait l'air à la façon dont elle a été appelée, et elle a conclu quedo_something()
finirait par être déclaré comme ceci:Pourquoi avait-il conclure que? Parce que c'est la façon dont vous appelé il! (Certains compilateurs C peut conclure qu'elle a été
int do_something(int arg1, int arg2)
, ou tout simplementint do_something(...)
, qui sont tous deux de même plus loin de ce que vous voulez, mais le point important est que, indépendamment de la façon dont le compilateur devine les types, il les devine différemment de ce que votre fonction utilise.)Plus tard, le compilateur recherche avant dans le fichier, il voit votre réelle déclaration de
char *do_something(char *, char *)
. Que la déclaration de la fonction n'est même pas près de la déclaration que le compilateur à deviner, ce qui signifie que la ligne où le compilateur compilé l'appel a été compilé mal, et le programme est tout simplement pas aller travailler. Donc, c'est à juste titre imprime une erreur vous indiquant que votre code n'est pas d'aller travailler comme écrit.Vous demandez peut-être, "Pourquoi faut-il que je suis de retour d'un
int
?" Eh bien, il suppose que type de, car il n'y a aucune information à l'effet contraire:printf()
peut prendre en tout type dans sa variable d'arguments, donc, sans une meilleure réponse,int
est aussi bon une supposition que tout. (Beaucoup des premiers compilateurs C toujours supposéint
pour chaque type non spécifié, et suppose que vous vouliez dire...
pour les arguments pour chaque fonction déclaréef()
— pasvoid
— qui est pourquoi beaucoup de code moderne normes recommandent de toujours mettrevoid
dans les arguments si il ne sont pas censé être le cas.)Le Correctif
Il y a deux solutions courantes pour la fonction-déclaration d'erreur.
La première solution, qui est recommandé par de nombreux autres réponses ici, est de mettre un prototype dans le code source ci-dessus l'endroit où la fonction est appelée en premier. Un prototype ressemble à la déclaration de la fonction, mais il a un point-virgule où le corps doit être:
En mettant le prototype d'abord, le compilateur puis sait ce que la fonction finira par ressembler, donc il n'a pas à deviner. Par convention, les programmeurs ont souvent mis les prototypes en haut du fichier, juste sous la
#include
états, pour s'assurer qu'ils vont toujours être défini avant tout le potentiel des usages d'entre eux.L'autre solution, qui montre également, dans certains codes réels, est tout simplement de modifier l'ordre de vos fonctions, de sorte que les déclarations de fonction sont toujours avant tout ce que les appels de! Vous pouvez déplacer l'ensemble de la
char *do_something(char *dest, const char *src) { ... }
fonction au-dessus du premier appel, et le compilateur serait alors de savoir exactement ce que la fonction ressemble et ne pas avoir à deviner.Dans la pratique, la plupart des gens utilisent les prototypes de fonction, parce que vous pouvez également prendre des prototypes de fonction et de les déplacer dans l'en-tête (
.h
) les fichiers de sorte que le code dans d'autres.c
fichiers pouvez appeler ces fonctions. Mais soit la solution fonctionne, et de nombreuses bases de codes utiliser les deux.C99 et C11
Il est utile de noter que les règles sont légèrement différentes dans les versions plus récentes de la norme. Dans les versions antérieures (C89 et K&R), le compilateur vraiment serait suppose que les types en fonction du temps d'appel (et K&R-era compilateurs souvent de ne même pas vous avertir si ils ont tort). C99 et C11 à la fois exiger que la déclaration de la fonction/prototype doit précéder le premier appel, et c'est une erreur s'il ne le fait pas. Mais de nombreux moderne compilateurs C — principalement pour des raisons de rétrocompatibilité avec les anciens de code ne avertir manque un prototype et ne pas la considérer comme une erreur.
C Commandement N ° 3:
http://www.ee.ryerson.ca:8080/~elfe/hack/Dieu.vs.K+R.html
Lorsque vous ne donnez pas le prototype de la fonction avant de l'utiliser, C suppose qu'il prend un nombre quelconque de paramètres et renvoie un int. Ainsi, lorsque vous essayez d'abord d'utiliser faire_quelque_chose, c'est le type de la fonction, le compilateur est à la recherche pour. Cela devrait produire un avertissement à propos d'un "implicite de la déclaration de la fonction".
Donc dans votre cas, lorsque vous déclarez la fonction plus tard, C ne permet pas de surcharge de fonctions, de sorte qu'il devient pissy parce que vous avez déclaré deux fonctions prototypes différents mais avec le même nom.
Réponse courte: déclarer la fonction avant de l'utiliser.
int foo()
(prend un nombre quelconque de paramètres) etint foo(void)
(ne prend pas de paramètres).Regarder à nouveau:
L'accent sur cette ligne:
Vous pouvez clairement voir que le faire_quelque_chose fonction n'est pas déclaré!
Si vous regardez un peu plus loin,
vous verrez que vous déclarez la fonction après vous l'utilisez.
Vous aurez besoin de modifier cette partie avec ce code:
Acclamations 😉
Cela se produit souvent lorsque vous modifiez une fonction c de définition et d'oublier de mettre à jour le correspondant de l'en-tête de définition.
Assurez-vous que les types dans la déclaration de fonction sont déclarés en premier.
/* start of the header file */
.
.
.
struct intr_frame{...}; //must be first!
.
.
.
void kill (struct intr_frame *);
.
.
.
/* end of the header file */