c - тип - указатель на элемент структуры




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

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

Бит кода переводится как: возьмите память, начиная с адреса s, и обработайте ее как память, указывающую на char . На этот адрес добавьте sizeof(int) char -chunks - вы получите новый адрес. Возьмите значение, созданное таким образом, и обработайте его как int .

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

Изменить: согласно комментарию Андрея, используя offsetof :

*((int *) ((byte *) s + offsetof(struct mystruct, member_b)))

Изменить 2: я заменил все byte s на char s, поскольку sizeof(char) гарантированно будет 1.

Игнорируя проблемы заполнения / выравнивания и учитывая следующую структуру, лучший способ получить и установить значение 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 для установки содержимого памяти

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

Приветствия за любую помощь


Возможно рассчитать смещение на основе структуры и NULL в качестве ссылочного указателя, например, « & (((type *) 0) -> field) "

Пример:

struct my_struct {
    int x;
    int y;
    int *m;
    int *h;
};
int main()
{
    printf("offset %d\n", (int) &((((struct my_struct*)0)->h)));
    return 0;
}

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

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

(аналогичные для других типов).


Подход, который вы наметили, примерно правильный, хотя вы должны использовать 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;
}




struct