GCC - структура, определяющая элементы в определенных смещениях - PullRequest
8 голосов
/ 23 ноября 2011

Есть ли способ в gcc, где я мог бы определить структуру с конкретным членом в определенном смещении?

Я хочу определить структуру следующим образом:

struct {
.offset(0xDC) //or something equivalent
   int bar;
} foo;

, а затем следующее утверждение:

int a = foo.bar

будет идентичным утверждению:

int a = *(int*)((char*)&foo + 0xDC);

* ОБНОВЛЕНИЕ *

Некоторый фон: Я хочу получить доступ к членам в экспортированной структуре, у которой нет правильного определения, у нее много членов - о которых я забочусь только о нескольких из них, и их смещение (исходное определение структуры) немного отличается на каждой целевой платформе нужно скомпилировать мой код для нескольких разных платформ)

Я рассмотрел вариант заполнения, упомянутый в комментариях здесь, но он требует от меня делать некоторые раздражающие вычисления каждый раз, когда я хочу добавить участника. например:

strcut {
.offset(0xDC)
    int bar;
.offset(0xF4)
    int moo;
}foo;

проще, чем:

struct __attribute__ ((__packed__)) struct {
   char pad1[0xD8];
   int bar;
   char pad2[0x18];
   int moo;
}foo;

и что без учета того факта, что sizeof (int) может изменяться от платформы к платформе

Ответы [ 6 ]

9 голосов
/ 23 ноября 2011

Вы должны взглянуть на __attribute__ ((__packed__)).

В вашем случае вы бы написали:

struct __attribute__ ((__packed__)) {
   char unused[0xDC];
   int bar;
} foo;

Если бы вы могли объяснить, что вы пытаетесь сделать, могут быть другие, возможно, более изящные решения.

3 голосов
/ 23 ноября 2011

Решение с использованием заполнения и объединения, как предложено в других ответах:

#include <stdio.h>

#define OFF_STRUCT(name, members) union { members } name

#define OFF_MEMB(offset, member)                 \
        struct __attribute__ ((__packed__)) {    \
                char pad[offset];                \
                member;                          \
        }

int main(int argc, char *argv[])
{
        OFF_STRUCT(foo,
                OFF_MEMB(0xD8, int bar);
                OFF_MEMB(0x18, double moo);
                OFF_MEMB(0x1, int bee);
        );

        printf("offset: 0x%x 0x%x 0x%x\n",
                (void*)&foo.bar - (void*)&foo,
                (void*)&foo.moo - (void*)&foo,
                (void*)&foo.bee - (void*)&foo
        );
}

Выход:

offset: 0xd8 0x18 0x1
2 голосов
/ 23 ноября 2011

Я рассмотрел вариант заполнения, упомянутый в комментариях здесь, но он требует от меня делать некоторые раздражающие вычисления каждый раз, когда я хочу добавить элемент.

Что касается раздражающих вычислений, выможете просто сгенерировать объявление вашей структуры, используя предпочитаемый вами язык сценариев:

struct = { 0xdc : (4, 'int bar'),
           0xf4 : (4, 'int moo') }

def print_struct_decl (name, decl):
        print "struct __attribute__ ((packed)) %s {" % name
        off = 0
        i = 0;
        for o in sorted (decl.keys()):
                print "\tchar pad%d [%d];" % (i, o - off)
                i = i + 1
                off = off + o + decl[o][0]
                print "\t%s;" % decl[o][1]
        print "};"

print_struct_decl ("whatever", struct)

Выходы:

struct __attribute__ ((packed)) whatever {
    char pad0 [220];
    int bar;
    char pad1 [20];
    int moo;
};
2 голосов
/ 23 ноября 2011

Вы всегда можете дополнить его байтами и убедиться, что вы говорите gcc не выравнивать свои структуры (так как это может сместить смещения).В этом случае вам понадобится член типа char pad_bytes[num_pad_bytes];.Хотя есть ли причина для этого?Вы всегда можете вычислить смещение члена структуры, выполнив некоторую арифметику указателя.Примечание: вы можете захотеть использовать тип uint8_t для дополнения вместо char, поскольку некоторые компиляторы могут дополнять char (который обычно является байтом) до размера слова.

Вычисление смещения так же просто, как

size_t offset = (size_t)&((struct_type *)0)->member);

Все, что это делает, это просто возвращает указатель на то, где член был бы в struct_type, если бы структура была в 0x00 в памяти (чего никогда не может быть), но поскольку мы используем 0 в качестве основы, то смещениепросто ссылка, возвращаемая оператором &.

1 голос
/ 23 ноября 2011

Я бы написал класс, который оборачивает указатель:

class whateverPtr {
    unsigned char *p;

public:
    whateverPtr(void *p) : p(reinterpret_cast<unsigned char *>(p) { }

    uint32_t getBar() const { return read_uint32(0xdc); }

private:
    uint32_t read_uint32(unsigned int offset) {
        return p[offset] |
            (p[offset + 1] << 8) |
            (p[offset + 2] << 16) |
            (p[offset + 3] << 24);
    }
};

Это полностью переносимое устройство, которое будет работать, как и ожидалось, на бигендовских архитектурах. Целые числа со знаком немного сложнее, так как вам нужно получить правильную кодировку.

0 голосов
/ 23 ноября 2011

Я не предлагаю делать это; структуры не предназначены для такого рода манипулирования данными. Если вам нужно изменить данные в определенном месте, используйте правильно введенный указатель, чтобы внести изменения таким образом. Добавление структур в смесь просто добавляет сложности без какой-либо выгоды.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...