2017-04-12 6 views
0

Ich habe eine etwas ungewöhnliche Frage. Da ich Reverse-Engineering-Code bin, kann die Datenstruktur (die übrigens schrecklich ist) nicht geändert werden. Zunächst einmal ist dies die Struktur, die jetzt meine Probleme verursacht:Array von Union mit Mitgliedern unterschiedlicher Größe

typedef struct { 
    build_field build; 
    u8 field_1; 
    u8 level; 
    u8 field_3; 
    u16 species; 
    union{ 
     struct { 
      u16 field_6; 
     } default_item_default_attacks; 
     struct { 
      u16 moves[4]; 
      u16 field_E; 
     } default_item_custom_attacks; 
     struct { 
      u16 item; 
     } custom_item_default_attacks; 
     struct { 
      u16 item; 
      u16 moves[4]; 
     } custom_item_custom_attacks; 
    } item_and_moves; 
} trainer_pokemon; 

Wie Sie die Größe der Struktur sehen trainer_pokemon variiert je nachdem, welche uninion Mitglied ich Instanciate verwenden. Das Problem ist, dass ich mehrere trainer_pokemon[] instanziieren muss. Wie erwartet, erweitert mein C-Compiler die Größe jedes Elements dieses Arrays auf das Maximum (als ob ich immer das Union-Element custom_item_custom_attacks für Instanziierung verwendet hätte). Das Spiel Reverse Engineering erwartet jedoch, dass die Mitglieder des Arrays der Größe der verwendeten Union entsprechen. Das mag etwas verwirrend klingen, so dass ich ein konkreteres Beispiel geben:

trainer_pokemon[] t = { 
       { 
         0x0, //build 
         0x0, //ability bit 
         false, //hidden ability 
         false, //shiny 
       }, 
       0x0, //field_1 
       8, //Level 
       0, //field_3 
       POKEMON_LICHTEL, { 
         .default_item_default_attacks = { 
           0x0, //field_6, 
         } 
       } 
     }, 
     { 
       { 
         0x0, //build 
         0x0, //ability bit 
         false, //hidden ability 
         false, //shiny 
       }, 
       0x0, //field_1 
       6, //Level 
       0, //field_3 
       POKEMON_TRAUMATO, 
       { 
         .default_item_default_attacks = { 
           0x0, //field_6, 
         } 
       } 
     } 
}; 

Wie Sie 8 Bytes pro Element dieses Arrays sehen würde ausreichen, um dieses Array zu instanziieren (Gesamtgröße 16 Byte). Jedoch ist jedes Mitglied bis zu einer Größe von 16 Bytes (Gesamtgröße von 32 Bytes) null-gefüllt, da der Compiler nur annimmt, dass ich mit custom_item_custom_attacks eingerichtet habe, was eine zusätzliche Menge von 8 Bytes erfordern würde. Das Problem ist, dass die Engine erwartet, dass die Struktur der Mindestgröße (in diesem Fall 8 Byte) entspricht. Wie kann ich dieses Problem am besten umgestalten oder beheben? Bitte beachten Sie auch, dass innerhalb eines Arrays alle Mitglieder die gleiche Größe haben und mit demselben Gewerkschaftsmitglied instanziiert werden müssen.

+0

'sizeof (trainer_pokemon)' wird um das größte Element in Ihrer Vereinigung erhöht. Wenn das das ist, was du meintest. – tilz0R

+0

Und das will ich verhindern. Ich denke, ich muss meine Datenstruktur umgestalten, aber wie? Gibt es einen besseren Weg? – PfannkuchenXD

+0

Was ist, wenn Sie Zeiger in der Seitenstruktur verwenden und dann Ihre Daten außerhalb dieser Variablen initiieren? Deine Struktur hält also den Zeiger irgendwo fest. Wenn es nicht null ist, wissen Sie, dass es einen gültigen Wert hat, andernfalls ignorieren Sie es. – tilz0R

Antwort

0

Es klingt wie, was Sie suchen, ist eine Art Polymorphismus (sp?). Stattdessen Gewerkschaften zu verwenden, können Sie Ihre Strukturen so etwas wie dieses

struct base_type 
    { 
    int type; 
    }; 

struct type_a 
    { 
    struct base_type base; 
    long some_value; 
    }; 

struct type_b 
    { 
    struct base_type base; 
    char tiny_value; 
    }; 

struct base_type *my_type_a=malloc(sizeof(struct type_a)); 
my_type_a.type=1; 
struct base_type *my_type_b=malloc(sizeof(struct type_b)); 
my_type_b.type=2; 
struct type_a *a=(struct type_a *) my_type_a; 

Sowohl die „Art“ structs teilen die gleichen gemeinsamen Attribute definieren, wie durch die base_type Struktur zur Verfügung gestellt, aber sie können unterschiedlich groß sein, wie erforderlich. Sie müssen nur sicherstellen, dass Sie beim Zuordnen des Speichers die richtigen Werte auffüllen, um korrekt erkennen zu können, um welche tatsächliche Struktur es sich handelt.

0

können Sie mehrere Strukturen verwenden und eine Basis-Struktur:

typedef struct { 
    build_field build; 
    u8 field_1; 
    u8 level; 
    u8 field_3; 
    u16 species; 
} trainer_pokemon_base; 

typedef struct { 
    build_field build; 
    u8 field_1; 
    u8 level; 
    u8 field_3; 
    u16 species; 

    u16 field_6; 
} trainer_pokemon_did; 

typedef struct { 
    build_field build; 
    u8 field_1; 
    u8 level; 
    u8 field_3; 
    u16 species; 

    u16 moves[4]; 
    u16 field_E; 
} trainer_pokemon_dic; 

typedef struct { 
    build_field build; 
    u8 field_1; 
    u8 level; 
    u8 field_3; 
    u16 species; 

    u16 item; 
} trainer_pokemon_cid; 

typedef struct { 
    build_field build; 
    u8 field_1; 
    u8 level; 
    u8 field_3; 
    u16 species; 

    u16 item; 
    u16 moves[4]; 
} trainer_pokemon_cic; 
0

ich mehrere verschiedene Strukturtypen verwenden würde:

typedef struct { 
    build_field build; 
    u8 field_1; 
    u8 level; 
    u8 field_3; 
    u16 species; 
} trainer_base; 

typedef struct { 
    trainer_base b; 
    u16 field_6; 
} trainer_pokemon_default_item_default_attacks; 

typedef struct { 
    trainer_base b; 
    u16 moves[4]; 
    u16 field_E; 
} trainer_pokemon_default_item_custom_attacks; 

typedef struct { 
    trainer_base b; 
    u16 item; 
} trainer_pokemon_custom_item_default_attacks; 

typedef struct { 
    trainer_base b; 
    u16 item; 
    u16 moves[4]; 
} trainer_pokemon_custom_item_custom_attacks; 

Sie auch einen benutzerdefinierten Typ definieren könnte, die jeder Typ kann „sein“ und wo Sie die zusätzlichen Felder als trainer->extra_field[i] zugreifen:

typedef struct { 
    trainer_base b; 
    u16 extra_field[0]; 
} trainer_pokemon; 

Sie würden verwenden die benutzerdefinierten Typ wie folgt aus:

trainer_pokemon *trainer = malloc(sizeof(trainer_pokemon_default_item_custom_attacks)); 
trainer->extra_field[2]; // This would access moves[2]. 
trainer->extra_field[4]; // This would access field_E. 

Hinweis: Sie benötigen besondere Sorgfalt bei der sizeof und Array-Arithmetik. Sie müssen immer den richtigen spezifischen Typ verwenden.

Hinweis: Sehr wichtig! Wenn Sie den benutzerdefinierten Typ und die anderen gemischten Typen verwenden, müssen Sie sich der strengen Aliasing-Regel und deren Auswirkungen bewusst sein. Wenn Sie die strenge Aliasing-Regel nicht gut kennen, sollten Sie die spezifischen Typen verwenden.

Verwandte Themen