déréférencement du pointeur vers un type incomplet
J'ai vu beaucoup de questions à ce sujet, mais je vais poser la question différemment sans code spécifique. Y a-t-il un moyen de facilement déterminer ce qui fait que le type est incomplet? Dans mon cas, j'utilise quelqu'un d'autre et je suis complètement sûr que je n'ai pas les en-têtes, mais (puisque les ordinateurs font ce genre de choses beaucoup plus vite et mieux que les globes oculaires humains) est-il possible d'obtenir le compilateur pour dire: "hey You think you have type X at line 34 but that's en fait manquant."L'erreur elle-même n'apparaît que lorsque vous assignez, ce qui n'est pas très utile.
7 réponses
J'ai vu une question l'autre jour où quelqu'un a utilisé par inadvertance un type incomplet en spécifiant quelque chose comme struct a { int q; }; struct A *x; x->q = 3;
. Le compilateur savait que struct A
était une structure, bien que A
soit totalement indéfini, en vertu du mot-clé struct
.
C'était en C++, où une telle utilisation de struct
est atypique (et, il s'avère, peut conduire à un tir au pied). En C si vous le faites
typedef struct a {
...
} a;
Ensuite, vous pouvez utiliser {[6] } comme nom de type et omettre le struct
plus tard. Cela conduira le compilateur à vous donner un erreur d'identifiant indéfini plus tard, plutôt que le type incomplet, si vous avez mal saisi le nom ou oublié un en-tête.
Que voulez-vous dire, l'erreur n'apparaît que lorsque vous assignez? Par exemple sur GCC, sans affectation en vue:
int main() {
struct blah *b = 0;
*b; // this is line 6
}
incompletetype.c:6: error: dereferencing pointer to incomplete type
.
L'erreur est à la ligne 6, c'est là où j'ai utilisé un type incomplète, comme si c'étaient un type. J'ai été très bien jusqu'alors.
L'erreur est que vous auriez dû inclure n'importe quel en-tête définissant le type. Mais le compilateur ne peut pas deviner quelle ligne aurait dû être incluse: toute ligne en dehors d'une fonction serait fine, assez bien. Il ne va pas non plus parcourir chaque fichier texte de votre système, à la recherche d'un en-tête qui le définit, et vous suggère de l'inclure.
Sinon (bon point, potatoswatter), l'erreur est à la ligne où b
a été défini, lorsque vous signifiait pour spécifier un type qui existe réellement, mais en fait spécifié blah
. Trouver la définition de la variable b
ne devrait pas être trop difficile dans la plupart des cas. IDEs peut généralement le faire pour vous, les avertissements du compilateur ne peuvent peut-être pas être dérangés. C'est un code assez odieux, cependant, si vous ne trouvez pas les définitions des choses que vous utilisez.
Je ne comprends pas exactement quel est le problème. Le type incomplet n'est pas le type "manquant". Incompete type est un type qui est déclaré, mais pas définie (dans le cas de types struct). Trouver la déclaration non définissante est facile. Comme pour la constatation du manque de définition... le compilateur ne vous aidera pas ici, puisque c'est ce qui a causé l'erreur en premier lieu.
Une des principales raisons des erreurs de type incomplètes en C sont les fautes de frappe dans les noms de type, qui empêchent compilateur de choisir un nom à l'autre (comme dans la correspondance de la déclaration de la définition). Mais encore une fois, le compilateur ne peut pas vous aider ici. Le compilateur ne fait pas de suppositions sur les fautes de frappe.
Une autre raison possible est la référence indirecte. Si un code fait référence à une structure qui n'est pas incluse dans le fichier c actuel, le compilateur se plaindra.
A->b->c //erreur si b n'est pas inclus dans le fichier c actuel
Cette erreur montre généralement si le nom de votre structure est différente de l'initialisation de votre structure dans le code, donc normalement, c de trouver le nom de la struct vous avez mis et si la structure n'est pas trouvé, ce serait généralement apparaissent, ou si vous pointez un pointeur pointant vers le pointeur, l'erreur s'affiche.
Une Solution
Parlant pour le langage C, je viens de trouver ampiriquement que le code de déclaration suivant sera la solution;
typedef struct ListNode
{
int data;
ListNode * prev;
ListNode * next;
} ListNode;
Donc, en règle générale, je donne le même nom à la fois pour la définition de type et le nom de la structure;
typedef struct X
{
// code for additional types here
X* prev; // reference to pointer
X* next; // reference to pointer
} X;
B - Échantillons Problématiques
Où les déclarations suivantes sont considérées comme incomplètes par le compilateur gcc
lors de l'exécution de l'instruction suivante. ;
removed->next->prev = removed->prev;
Et j'obtiens la même erreur pour le code de déréférencement signalé dans la sortie d'erreur;
>gcc Main.c LinkedList.c -o Main.exe -w
LinkedList.c: In function 'removeFromList':
LinkedList.c:166:18: error: dereferencing pointer to incomplete type 'struct ListNode'
removed->next->prev = removed->prev;
Pour les deux déclarations du fichier d'en-tête énumérées ci-dessous;
typedef struct
{
int data;
ListNode * prev;
ListNode * next;
} ListNode;
, Plus celui-ci;
typedef struct ListNodeType
{
int data;
ListNode * prev;
ListNode * next;
} ListNode;
En dehors des scénarios possibles impliquant l'optimisation de l'ensemble du programme, le code de code généré pour quelque chose comme:
struct foo *bar;
struct foo *test(struct foo *whatever, int blah)
{
return blah ? whatever: bar;
}
Sera totalement affecté par ce que les membres {[1] } pourraient contenir. Étant donné que make utilities recompile généralement toute unité de compilation dans laquelle la définition complète d'une structure apparaît, même si de telles modifications ne peuvent pas réellement affecter le code généré pour elles, il est courant d'omettre les définitions de structure complètes des unités de compilation qui ne le font pas réellement besoin d'eux, et cette omission n'est généralement pas digne d'un avertissement.
Un compilateur doit avoir une structure complète ou une définition d'union pour savoir comment gérer les objets declarations du type avec une durée automatique ou statique, les déclarations d'agrégats contenant des membres du type, ou le code qui accède aux membres de la structure ou de l'union. Si le compilateur n'a pas les informations nécessaires pour effectuer l'une des opérations ci-dessus, il n'aura aucun choix mais pour affichez sur il.
Incidemment, il y a une autre situation où la norme permettrait à un compilateur d'exiger une définition d'union complète pour être visible mais ne nécessiterait pas de diagnostic: si deux structures commencent par une séquence initiale commune, et un type d'union contenant les deux est visible lorsque le compilateur traite du code qui utilise un pointeur de l'un des types accès au membre correspondant d'une structure de l'autre type. Je ne sais pas quels compilateurs se conforment à la NORME Lorsque le type d'union complet est visible mais pas quand il ne l'est pas [gcc est enclin à générer du code non conforme dans les deux cas sauf si l'indicateur -fno-strict-aliasing
est utilisé, auquel cas il générera du code conforme dans les deux cas] mais si l'on veut écrire du code qui cette définition de type d'union complète est visible; à défaut de le faire, un compilateur peut générer silencieusement du code faux.