Как я могу получить/установить участника структуры погашением

Игнорирование проблем дополнения/выравнивания и, учитывая следующую структуру, что лучший способ состоит в том, чтобы получить и установить значение member_b, не используя членское имя.

struct mystruct {
    int member_a;
    int member_b;
}
struct mystruct *s = malloc(sizeof(struct mystruct));

Другими словами; Как был бы Вы выражать следующее с точки зрения указателей/погашений:

s->member_b = 3;
printf("%i",s->member_b);

Мое предположение к

  • вычислите погашение, найдя sizeof member_a (int)
  • бросьте структуру к типу указателя отдельного слова (char?)
  • создайте int указатель и набор адрес (к *charpointer + offset?)
  • используйте мой int указатель, чтобы установить содержание памяти

но я становлюсь немного смущенным кастингом к типу случайной работы или если что-то как memset более соответствующее или если обычно я - aproching это полностью неправильно.

Аплодисменты для любой помощи

27
задан Chris Farmiloe 11 January 2010 в 18:21
поделиться

5 ответов

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

Вот какой-то код, чтобы продемонстрировать, как он работает:

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>

typedef struct x {
    int member_a;
    int member_b;
} x;

int main() { 
    x *s = malloc(sizeof(x));
    char *base;
    size_t offset;
    int *b;

    // initialize both members to known values
    s->member_a = 1;
    s->member_b = 2;

    // get base address
    base = (char *)s;

    // and the offset to member_b
    offset = offsetof(x, member_b);

    // Compute address of member_b
    b = (int *)(base+offset);

    // write to member_b via our pointer
    *b = 10;

    // print out via name, to show it was changed to new value.
    printf("%d\n", s->member_b);
    return 0;
}
33
ответ дан 28 November 2019 в 04:37
поделиться

Полная техника:

  1. Получить смещение с использованием OffsetOf:

    b_Offset = Offsetof (Brack mystruct, member_b);

  2. Получить адрес вашей структуры в виде указателя Char * Отказ

    CHAR * SC = (CHAR *) S;

  3. Добавьте добавить смещение в адрес структуры, отставьте значение указателю на соответствующий тип и развесел:

    * (int *) (SC + b_offset)

26
ответ дан 28 November 2019 в 04:37
поделиться

Игнорируя обивку и выравнивание, как вы сказали...

Если элементы, на которые вы указываете, полностью одного типа, как в вашем примере, вы можете просто привести структуру к нужному типу и рассматривать ее как массив:

printf("%i", ((int *)(&s))[1]);
4
ответ дан 28 November 2019 в 04:37
поделиться

Это Звучит от ваших комментариев, что вы действительно делаете, - это упаковка и распаковка куча разрозненных типов данных в один блок памяти. Пока вы могут уйти с тем, что с прямым указателем, поскольку предложили большинство других ответов:

void set_int(void *block, size_t offset, int val)
{
    char *p = block;

    *(int *)(p + offset) = val;
}

int get_int(void *block, size_t offset)
{
    char *p = block;

    return *(int *)(p + offset);
}

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

Чтобы сделать это портативно, вам необходимо использовать memcpy :

void set_int(void *block, size_t offset, int val)
{
    char *p = block;

    memcpy(p + offset, &val, sizeof val);
}

int get_int(void *block, size_t offset)
{
    char *p = block;
    int val;

    memcpy(&val, p + offset, sizeof val);
    return val;
}

(аналогично другим типам).

0
ответ дан 28 November 2019 в 04:37
поделиться

В этом конкретном примере, можно обратиться к нему * ((интервал *) ((символ *) s + sizeof (интервал))) . Я не уверен, почему вы хотите это, таким образом, я принимаю дидактические цели, поэтому объяснение следует.

бит кода переводит как: взять память, запускающуюся в адресе s, и рассматривать его как память, указывающую символ . К тому адресу добавьте sizeof (интервал) символ - блоки - вы получите новый адрес. Принять значение, что адрес, таким образом созданный и, рассматривает его как интервал .

Примечание, что запись * (s + sizeof (интервал)) дала бы адрес в s плюс sizeof (интервал) sizeof (mystruct) блоки

Редактирование: согласно комментарию Andrey, с помощью offsetof:

* ((интервал *) ((байт *) s + offsetof (структура mystruct, member_b)))

Редактирование 2: Я заменил весь байт с с символ с как , sizeof (символ) , как гарантируют, будет 1.

1
ответ дан 28 November 2019 в 04:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: