Доступ к любым структурам членов во время выполнения - PullRequest
0 голосов
/ 08 апреля 2010

Можно ли получить доступ к отдельному члену структуры или класса, не зная имен его переменных-членов? Я хотел бы сделать «offsetof (struct, tyname)» без жестко запрограммированного имени структуры или имени члена-члена среди других вещей. спасибо.

Ответы [ 6 ]

4 голосов
/ 08 апреля 2010

Конечно. Если у вас есть структура и вы знаете смещение и тип переменной-члена, вы можете получить к ней доступ с помощью указателей.

struct my_struct {
    int member1;
    char member2;
    short member3;
    char member4;
}

...

struct my_struct obj;
short member3 = *((short*)((char*)&obj + 5));

Получит значение member3, что составляет 5 байт с начала obj на компьютере с архитектурой x86. Тем не менее, вы хотите быть осторожным. Прежде всего, если структура изменится, ваши данные будут мусором. Мы проводим повсеместную трансляцию, так что вы не получаете безопасность типов, и компилятор не предупредит вас, если что-то не так. Вам также необходимо убедиться, что компилятор не упаковывает структуру для выравнивания переменных по границам слов, иначе смещение изменится.

Это не из приятных вещей, и я бы избежал этого на вашем месте, но да, это можно сделать.

1 голос
/ 08 апреля 2010

У нас была похожая проблема несколько лет назад: огромная структура информации о конфигурации, которую мы хотели отразить. Поэтому мы написали сценарий Perl, чтобы найти структуру, проанализировать ее члены и вывести файл C ++, который выглядел следующим образом:

struct ConfField
{    const char* name;
     int type;
     size_t offset;
};

ConfField confFields[] = {
    { "version", eUInt32, 0 },
    { "seqID", eUInt32, 4 },
    { "timestamp", eUInt64, 8 },
    // ... lots more ...
    { 0, 0, 0 }
};

И мы бы подали скрипт с выводом gcc -E.

В настоящее время я понимаю, что gccxml может выводить XML-файл, представляющий любой исходный код C ++, который может компилировать gcc, поскольку он фактически использует внешний интерфейс g ++ для анализа. Поэтому я бы порекомендовал соединить его со скриптом синтаксического анализа XML (я бы использовал Python с библиотекой lxml ), чтобы узнать все, что вы когда-либо хотели знать о вашем источнике C ++.

1 голос
/ 08 апреля 2010

C и C ++ являются скомпилированными языками без встроенных функций «отражения». Это означает, что независимо от того, что вы делаете и как вы это делаете, путь всегда будет начинаться с явного жестко заданного значения, будь то имя члена или значение смещения во время компиляции. Это означает, что если вы хотите выбрать элемент структуры на основе некоторого ключа времени выполнения, у вас нет другого выбора, кроме как вручную создать какое-либо отображение, которое сопоставило бы значение ключа чему-то, что идентифицирует конкретный элемент структуры. *

В C ++ для идентификации члена структуры во время выполнения вы можете использовать такую ​​функцию, как указатели на члены. В C ваш единственный выбор - использовать значение смещения.

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

0 голосов
/ 08 апреля 2010

Ну, сначала вам нужно будет кое-что настроить, но это можно сделать.Расширяя ответ Самира

struct my_struct {
    int member1;
    char member2;
    short member3;
    char member4;
}

, вы можете создать таблицу смещений:

my_struct tmp;
int my_struct_offsets[4]={
  0,
  (char*)&(tmp.member2)-(char*)&(tmp.member1),
  (char*)&(tmp.member3)-(char*)&(tmp.member1),
  (char*)&(tmp.member4)-(char*)&(tmp.member1)
}

, это будет учитывать различные выравнивания в разных системах

0 голосов
/ 08 апреля 2010

Технический ответ - «да», потому что C ++ полон по Тьюрингу, и вы можете сделать почти все, если постараетесь. Более практичный ответ, вероятно, «нет», поскольку не существует безопасного и простого способа сделать именно то, что вы хотите.

Я согласен с GMan. Что именно вы пытаетесь сделать, что заставляет вас думать, что вам нужна эта техника?

0 голосов
/ 08 апреля 2010

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

struct foo
{
    int member1;
    int member2;
};

typedef int (foo::*intMemberOfFoo);

intMemberOfFoo getMember()
{
    if (rand() > RAND_MAX / 2) return &foo::member1;
    else return &foo::member2;
}

foo f;
void do_somthing()
{
    intMemberOfFoo m = getMember();
    f.*m = 0;
}
...