web-dev-qa-db-fra.com

pointeur de déréférencement sur le type incomplet

J'ai vu beaucoup de questions à ce sujet mais je vais poser la question différemment sans code spécifique. Existe-t-il un moyen deFACILEMENTde déterminer ce qui rend le type incomplet? Dans mon cas, j'utilise le code de quelqu'un d'autre et je suis tout à fait sûr que les en-têtes ne sont pas corrects, mais (puisque les ordinateurs le font beaucoup plus rapidement et mieux que les yeux humains), existe-t-il un moyen de faire dire au compilateur , "hé vous pensez que vous avez le type X à la ligne 34 mais c'est en fait manquant." L'erreur elle-même ne s'affiche que lorsque vous affectez, ce qui n'est pas très utile.

55
nick

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 non défini, en vertu du mot clé struct.

C'était en C++, où un tel usage de struct est atypique (et peut même conduire à des tirs à pied). En C si tu le fais

typedef struct a {
    ...
} a;

alors vous pouvez utiliser a comme nom de type et omettre la struct plus tard. Cela amènera le compilateur à vous donner ultérieurement une erreur d’identificateur indéfini, plutôt qu’un type incomplet, si vous entrez un nom ou si vous oubliez un en-tête.

44
Potatoswatter

Que voulez-vous dire, l'erreur n'apparaît que lorsque vous attribuez? Par exemple sur GCC, sans cession 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à que j'ai utilisé un type incomplet comme s'il s'agissait d'un type complet. J'allais bien jusque là.

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 très bien. Il ne va pas non plus parcourir tous les fichiers texte de votre système, rechercher un en-tête qui le définit et vous suggérer de l'inclure.

Alternativement (bon point, potatoswatter), l'erreur est à la ligne où b a été défini, quand vous vouliez dire pour spécifier un type qui existe réellement mais que vous avez spécifié blah. Trouver la définition de la variable b ne devrait pas être trop difficile dans la plupart des cas. Les IDE peuvent 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.

9
Steve Jessop

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

8
Steeven Li

Je ne comprends pas exactement quel est le problème. Le type incomplet n'est pas le type "manquant". Le type Incompete est un type qui est déclaré mais pas défini (dans le cas de types struct). Pour trouver la déclaration non-définir est facile. Pour ce qui est de trouver la définition manquante ... le compilateur ne vous aidera pas ici, car c’est ce qui a causé l’erreur en premier lieu.

Les fautes de frappe dans les noms de types empêchent le compilateur de faire correspondre un nom à un autre (comme dans la correspondance de la déclaration avec 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.

7
AnT

cette erreur indique généralement si le nom de votre structure diffère de l'initialisation de votre structure dans le code, donc normalement, c trouvera le nom de la structure que vous avez mis et si la structure d'origine n'est pas trouvée, il apparaîtra habituellement si vous pointez un pointeur pointant dans ce pointeur, l'erreur sera affichée.

1
catzilla_waw

Une solution

Parlant pour le langage C, je viens de constater avec amertume 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 du 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 à la fois comme incomplètes par le compilateur gcc lors de l'exécution de l'instruction suivante. ;

removed->next->prev = removed->prev;

Et je reçois la même erreur pour le code de déréférencement rapporté 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 fichier en-tête déclarations listé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;
0
Levent Divilioglu

En dehors des scénarios possibles impliquant une optimisation de tout le programme, le code généré pour quelque chose comme:

struct foo *bar;
struct foo *test(struct foo *whatever, int blah)
{
  return blah ? whatever: bar;
}

ne sera absolument pas affecté par ce que les membres struct foo pourraient contenir. Comme les utilitaires make recompilent généralement toutes les unités de compilation dans lesquelles la définition complète d'une structure apparaît, même si ces modifications ne peuvent pas affecter le code généré, il est courant d'omettre les définitions de structure complètes des unités de compilation qui n'en ont pas réellement besoin. eux, et une telle 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 déclarations d'objets du type à durée automatique ou statique, les déclarations d'agrégats contenant des membres du type ou le code permettant d'accéder aux membres de la structure ou de l'union. Si le compilateur ne dispose pas des informations nécessaires pour effectuer l'une des opérations ci-dessus, il n'aura d'autre choix que d'en parler.

Incidemment, il existe une autre situation dans laquelle la norme permet à un compilateur d’exiger la définition d’une union complète sans exiger de diagnostic: si deux structures commencent par une séquence initiale commune et que le type d’union les contenant est visible lorsque le compilateur Si le code de traitement utilise un pointeur de l’un des types de structure pour inspecter un membre de cette séquence initiale commune, le compilateur doit reconnaître qu’un tel code pourrait accéder au membre correspondant d’une structure de l’autre type. Je ne sais pas quels compilateurs sont conformes à la norme lorsque le type d'union complet est visible, mais pas quand il ne l'est pas [gcc a tendance à générer du code non conforme dans les deux cas sauf si le drapeau -fno-strict-aliasing est utilisé, auquel cas il générera un code conforme dans les deux cas] mais si vous voulez écrire du code qui utilise la règle CIS de manière à garantir un comportement correct sur les compilateurs conformes, vous devrez peut-être vous assurer que la définition complète du type d'union est visible; faute de quoi, un compilateur peut générer silencieusement un code factice.

0
supercat