webentwicklung-frage-antwort-db.com.de

dereferenzierender Zeiger auf unvollständigen Typ

Ich habe eine Menge Fragen dazu gesehen, aber ich werde die Frage ohne spezifischen Code anders stellen. Gibt es eine Möglichkeit, LEICHT zu bestimmen, was den Typ unvollständig macht? In meinem Fall verwende ich jemand anderen Code und bin absolut sicher, dass ich die Header nicht richtig habe, aber (da Computer dieses Zeug viel schneller und besser als menschliche Augäpfel machen), gibt es eine Möglichkeit, den Compiler dazu zu bringen , "hey Sie denke Sie haben X in Zeile 34 eingegeben, aber das ist fehlt." Der Fehler selbst wird nur beim Zuweisen angezeigt, was nicht sehr hilfreich ist.

55
nick

Neulich sah ich eine Frage, als jemand versehentlich einen unvollständigen Typ verwendete, indem er etwas wie struct a { int q; }; struct A *x; x->q = 3; spezifizierte. Der Compiler wusste, dass struct A eine Struktur ist, obwohl A aufgrund des Schlüsselworts struct völlig undefiniert ist.

Das war in C++, wo eine solche Verwendung von struct atypisch ist (und es stellt sich heraus, dass dies zu Fußschüssen führen kann). In C, wenn du es tust

typedef struct a {
    ...
} a;

dann können Sie a als Typname verwenden und die struct später weglassen. Dies führt dazu, dass der Compiler Ihnen später einen nicht definierten Bezeichner-Fehler und nicht einen unvollständigen Typ gibt, wenn Sie den Namen falsch eingeben oder einen Header vergessen.

44
Potatoswatter

Was meinst du damit, der Fehler erscheint nur beim Zuweisen? Zum Beispiel auf GCC, ohne Zuordnung in Sicht:

int main() {
    struct blah *b = 0;
    *b; // this is line 6
}

incompletetype.c:6: error: dereferencing pointer to incomplete type.

Der Fehler ist in Zeile 6, dort habe ich einen unvollständigen Typ verwendet, als wäre es ein vollständiger Typ. Bis dahin ging es mir gut.

Der Fehler ist, dass Sie den Header enthalten haben, der den Typ definiert. Der Compiler kann jedoch unmöglich erraten, in welcher Zeile die Zeile hätte eingefügt werden sollen: Jede Zeile außerhalb einer Funktion wäre in Ordnung. Es wird auch nicht jede Textdatei in Ihrem System durchsuchen, nach einem Header suchen, der sie definiert, und vorschlagen, dass Sie diese einfügen.

Alternativ (guter Punkt, Potatoswatter) liegt der Fehler in der Zeile, in der b definiert wurde, wenn Sie bedeutete einen Typ angeben, der tatsächlich existiert, aber tatsächlich blah. Die Definition der Variablen b zu finden, sollte in den meisten Fällen nicht zu schwierig sein. IDEs können dies normalerweise für Sie tun, Compiler-Warnungen können nicht gestört werden. Es ist jedoch ein ziemlich abscheulicher Code, wenn Sie die Definitionen der Dinge, die Sie verwenden, nicht finden können.

9
Steve Jessop

Ein weiterer möglicher Grund ist der indirekte Hinweis. Wenn ein Code auf eine Struktur verweist, die nicht in der aktuellen c-Datei enthalten ist, wird der Compiler eine Beschwerde einlegen.

a-> b-> c // Fehler, wenn b nicht in der aktuellen c-Datei enthalten ist

8
Steeven Li

Ich verstehe nicht genau, was das Problem ist. Ein unvollständiger Typ ist nicht der Typ, der "fehlt". Inkompetenter Typ ist ein Typ, der deklariert ist, aber nicht definiert (bei Strukturtypen). Die nicht definierende Deklaration zu finden ist einfach. Was das Finden der fehlenden Definition angeht, hilft Ihnen der Compiler hier nicht, da dies den Fehler überhaupt verursacht hat.

Ein Hauptgrund für unvollständige Typfehler in C sind Tippfehler in Typnamen, die verhindern, dass der Compiler einen Namen mit dem anderen übereinstimmt (z. B. wenn die Deklaration mit der Definition übereinstimmt). Der Compiler kann Ihnen hier jedoch nicht weiterhelfen. Der Compiler macht keine Tippfehler.

7
AnT

dieser Fehler zeigt normalerweise an, wenn der Name Ihrer Struktur sich von der Initialisierung Ihrer Struktur im Code unterscheidet. Normalerweise findet c den Namen der Struktur, die Sie setzen, und wenn die ursprüngliche Struktur nicht gefunden wird, wird diese normalerweise angezeigt oder Wenn Sie einen Zeiger auf diesen Zeiger zeigen, wird der Fehler angezeigt.

1
catzilla_waw

Eine Lösung

Ich spreche für die Sprache C und habe gerade festgestellt, dass der folgende Deklarationscode die Lösung ist.

typedef struct ListNode
{
    int data;
    ListNode * prev;
    ListNode * next;
} ListNode;

Als allgemeine Regel gebe ich also sowohl für die Typdefinition als auch für den Namen der Struktur den gleichen Namen.

typedef struct X
{
    // code for additional types here
    X* prev; // reference to pointer
    X* next; // reference to pointer
} X;

B - Problematische Proben

Wobei die folgenden Deklarationen vom Compiler gcc als unvollständig betrachtet werden, wenn die folgende Anweisung ausgeführt wird. ;

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

Ich bekomme denselben Fehler für den in der Fehlerausgabe gemeldeten Dereferenzierungscode.

>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;

Für die beiden unten aufgelistetenheader -Dateideklarationen;

typedef struct
{
    int data;
    ListNode * prev;
    ListNode * next;
} ListNode;

Plus diesen einen;

typedef struct ListNodeType
{
    int data;
    ListNode * prev;
    ListNode * next;
} ListNode;
0

Außerhalb möglicher Szenarien, die die Optimierung des gesamten Programms betreffen, wird der Code wie folgt generiert:

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

wird davon unberührt bleiben, was Mitglieder struct foo enthalten könnten. Da make-Dienstprogramme im Allgemeinen alle Kompilierungseinheiten neu kompilieren, in denen die vollständige Definition einer Struktur vorkommt, selbst wenn solche Änderungen den für sie generierten Code nicht beeinflussen konnten, werden in der Regel keine vollständigen Strukturdefinitionen aus Kompilierungseinheiten ausgelassen, die nicht wirklich benötigt werden und diese Unterlassung ist in der Regel keine Warnung wert.

Ein Compiler muss über eine vollständige Struktur- oder Vereinigungsdefinition verfügen, um zu wissen, wie Deklarationsobjekte des Typs mit automatischer oder statischer Dauer behandelt werden, Deklarationen von Aggregaten, die Mitglieder des Typs enthalten, oder Code, der auf Mitglieder der Struktur oder Vereinigung zugreift. Wenn der Compiler nicht über die erforderlichen Informationen verfügt, um eine der oben genannten Operationen auszuführen, hat er keine andere Wahl, als darüber zu quatschen.

Im Übrigen gibt es eine weitere Situation, in der der Standard es einem Compiler erlaubt, eine vollständige Definition der Union erforderlich zu machen, aber keine Diagnose erfordern würde: Wenn zwei Strukturen mit einer Common Initial Sequence beginnen, und ein Unionstyp, der beide enthält, ist beim Compiler sichtbar Ist ein Verarbeitungscode, der einen Zeiger auf einen der Strukturtypen verwendet, um ein Member dieser Common Initial Sequence zu untersuchen, muss der Compiler erkennen, dass dieser Code möglicherweise auf das entsprechende Member einer Struktur des anderen Typs zugreift. Ich weiß nicht, welche Compiler dem Standard entsprechen, wenn der vollständige Union-Typ sichtbar ist, aber nicht, wenn dies nicht der Fall ist. [Gcc neigt in jedem Fall dazu, nichtkonformen Code zu generieren, es sei denn, in diesem Fall wird das Flag -fno-strict-aliasing verwendet In beiden Fällen wird konformer Code generiert.] Wenn Sie jedoch Code schreiben möchten, der die CIS-Regel auf eine solche Weise verwendet, dass ein korrektes Verhalten auf kompatiblen Compilern gewährleistet ist, müssen Sie möglicherweise sicherstellen, dass die vollständige Definition des Union-Typs sichtbar ist. Andernfalls kann ein Compiler fälschlicherweise Code erzeugen.

0
supercat