与不同大小

时间:2017-04-12 13:07:59

标签: c arrays unions

我有一个不寻常的问题。由于我是逆向工程代码,因此我使用的数据结构(顺便说一下这很糟糕)无法更改。首先,这是导致我麻烦的结构:

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;

正如您所看到的,结构trainer_pokemon的大小取决于我使用哪个uninion成员进行实例化。问题是我需要实现几个trainer_pokemon[]。正如预期的那样,我的C-Compiler只是将这个数组的每个成员的大小扩展到最大值(好像我总是使用工会成员custom_item_custom_attacks进行实例化)。然而,我正在逆向工程的游戏期望阵列的成员匹配所使用的联合的大小。这可能听起来有些令人困惑,所以我将提供一个更具体的例子:

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

正如您所看到的,此数组的每个元素的8个字节足以实现此数组(总大小为16个字节)。但是,每个成员都填充为零,大小为16个字节(总大小为32个字节),因为编译器只假设我使用custom_item_custom_attacks实例化,这需要额外的8个字节。问题是游戏引擎期望结构适合最小尺寸(在这种情况下为8个字节)。 如何最好地重新安装或修复此问题?另请注意,在一个数组中,所有成员都具有相同的大小,并且必须使用相同的联合成员进行实例化。

3 个答案:

答案 0 :(得分:0)

听起来你所追求的是某种多态性(sp?)。您可以定义类似于

的结构,而不是使用联合
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;

“type”结构体共享与base_type结构提供的相同的公共属性,但它们可以根据需要具有不同的大小。您只需要确保在分配内存时填充正确的值,以便能够正确识别它是哪个实际结构。

答案 1 :(得分:0)

您可以使用多个结构和基础结构:

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;

答案 2 :(得分:0)

我会使用几种不同的结构类型:

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;

您还可以定义一个可以“成为”任何类型的自定义类型,以及您可以在trainer->extra_field[i]访问额外字段的位置:

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

您可以使用这样的自定义类型:

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.

注意:使用sizeof和数组运算时需要特别小心。您始终需要使用正确的特定类型。

注意:非常重要!如果您使用自定义类型和其他类型混合,那么您需要非常了解严格别名规则及其含义。如果您不熟悉严格的别名规则,则应坚持使用特定类型。