2016-07-07 13 views
-3

Ich möchte einen Zeiger auf eine von zwei Strukturen abhängig vom Wert einer Variablen zu werfen. Ich versuche dies, aber es funktioniert nicht -C - Cast void Zeiger auf die Struktur dynamisch

struct typeA 
{ 
    int a; 
    int x; 
} 
struct typeB 
{ 
    int b; 
    int a; 
    int x; 
    int z; 
} 


int band=1; 
void *ptr; 

if(band == 1) 
      ptr = (struct typeA *)malloc(sizeof(struct typeA)); 
else if(band == 2) 
      ptr = (struct typeB *)malloc(sizeof(struct typeB)); 

printf("A:%d",ptr->a);//error: structure type required instead of void 

Was wäre der beste Weg, dies zu tun?

EDIT: Strukturdefinitionen und Fehler (in Code-Kommentaren) hinzugefügt, um mehr Sinn zu machen.

+2

Cast ist nicht notwendig in C. (Auch 'ptr' ist' void * ') Bitte erklären Sie das" nicht funktioniert ". – BLUEPIXY

+1

Ich habe abgelehnt, weil Sie sagen, dass Ihr Code nicht funktioniert, aber Sie sagen nicht, warum, was ist der Fehler oder die Warnung, die der Compiler Ihnen gibt. Ändern Sie Ihre Frage mit dieser Info und ich werde meinen Downvote entfernen. – nbro

+0

Beenden Sie die Umwandlung von 'malloc()', geben Sie aber 'ptr' einen echten Typ. Wenn es wirklich einen guten Grund dafür gibt, dass "ptr" 'void *' ist, dann weise einfach die größere der beiden Größen zu. Und, ähm, * "es funktioniert nicht" * ist eine schreckliche Beschreibung Ihres Problems. Fügen Sie die Fehlermeldung hinzu! – DigitalRoss

Antwort

1

Wenn Sie nicht wissen müssen, welche Art von Struktur, die Sie haben, verwenden Sie

if(band == 1) 
     ptr = malloc(sizeof(struct typeA)); 
else if(band == 2) 
     ptr = malloc(sizeof(struct typeB)); 

Der Rückgabetyp malloc bereits void * ist.

Dies ist jedoch ein code smell --- do you wirklich nicht die Größe oder Art der Struktur müssen wissen, nachdem Sie es schaffen? Ich würde dein Design ein wenig überdenken.

Bearbeiten Basierend auf dem zusätzlichen Code, den Sie gepostet haben, empfehle ich dringend einen neuen Ansatz. Zum Beispiel sind die Felder in typeA und typeB in einer anderen Reihenfolge, so dass es keine Möglichkeit für ptr->a gibt, sich auf beide zu beziehen, unabhängig vom Typ ptr. Wenn Sie mit reinem C festgefahren sind, betrachten Sie einen struct, der a und x und einen optionalen Zeiger auf eine separate Struktur mit b und z hat. Alternativ verwenden Sie einfach typeB für alles und entfernen Sie typeA!

1

Sie sollten das Ergebnis von malloc niemals umsetzen, da dies andere Probleme maskieren kann. Es verursacht auch hier eine Warnung, weil die Typen nicht übereinstimmen.

Entfernen Sie die Gussformen, und Sie sollten keine Warnungen erhalten.

EDIT:

Der Fehler ist, weil Sie zu dereferenzieren ein void * sind versucht, die illegal ist.

Anstatt eine Variable zu verwenden, verwenden Sie zwei (eine von jedem Typ) und setzen Sie die andere auf NULL. Wenn Sie alternativ den Typ der Daten kennen, die auf void * zeigen, können Sie sie in den richtigen Typ umwandeln und dann deneferenzieren.

+0

Typen stimmen nicht überein, aber' void * 'ist der allgemeinste Typ von Zeiger, daher sollte es kein Problem sein, zuzuordnen ein Zeiger auf einen anderen Typ zu einem 'void *', oder liege ich falsch? Nicht der Downvoter. – nbro

1

Die Casts hier kaufen Sie nichts, weil das Ergebnis jeder Besetzung sofort in den Typ ptr konvertiert wird. In jedem Fall endet der Zeiger auf das Objekt malloc -ed in ptr, und ptr hat genau einen statischen Typ, der exakt dem entspricht, was malloc zurückgibt. Das einzige Verhalten, das sich unterscheidet, ist die Größe der Region malloc -ed.

Ihre Logik kann auf einen Einzeiler reduziert werden:

void *ptr = malloc(band == 1 ? sizeof (struct typeA) : sizeof (struct typeB)); 

Viel mehr Kontext erforderlich ist, um zu sehen, ob dies im Hinblick auf den umgebenden Code ein guter Ansatz ist, oder ob etwas eine „OOP diszipliniert ähnlich "wäre besser, oder ob ein einfacher Wechsel zwischen zwei separaten Teilen des Codes auf separaten Strukturen arbeiten.

Das eigentliche Objekt kann nicht als typeA oder typeB ohne zusätzliche Abgüsse zugegriffen werden, so kann es, dass viele hässlichen Code vorstellen folgt, wie

if (band == 1) 
    do_this_A_version((struct typeA *) ptr)->foo, x); 
else 
    do_this_B_version((struct typeB *) ptr)->bar, y); 

gibt es gute Möglichkeiten, diese Art zu vermeiden Ding, für diese Frage außerhalb des Geltungsbereichs.

1

[EDIT] Code-Snippet aktualisiert, nachdem das OP bearbeitet wurde.

Dies ist die zweite Frage tatsächlichen Frage, aber vielleicht ist das folgende was Sie sind nach.

2

Wie andere vorgeschlagen haben, müssen Sie möglicherweise Ihr Design ändern, da es einige Fehler hat.

jedoch die Kompilierung Fehler zu beheben, Sie werden immer Sie etwas tun können:

printf("A:%d",(band == 1) ? ((struct typeA *)ptr)->a : ((struct typeB *)ptr)->a); 

Sie Fehler bekommen, weil Sie Mitglied zuzugreifen versuchen a von einem void * wenn Sie das tun (ptr->a).

Sie müssen es umwandeln, um zu sagen, dass ptr auf eine struct typeA oder struct typeB verweist.