Приведите структуру целых к массиву целых - PullRequest
3 голосов
/ 21 марта 2011

Я использую библиотеку, в которой есть функция, которая принимает массив структур. Эта структура и функция имеют следующую компоновку:

struct TwoInt32s
{
  int32_t a;
  int32_t b;
};

void write(struct TwoInt32s *buffer, int len);

Мои первоначальные тесты показывают, что массив таких структур имеет ту же структуру памяти, что и массив int32_t, поэтому я могу сделать что-то вроде этого:

int32_t *buffer = malloc(2 * len * sizeof(int32_t));
/* fill in the buffer */
write((struct TwoInt32s*)buffer, len);

Однако мне интересно, правда ли это универсально или нет. Использование массива int32_t значительно упрощает мой код.

РЕДАКТИРОВАТЬ: я забыл размер

Из того, что я прочитал, C гарантирует несколько вещей о заполнении структуры:

  1. Члены НЕ будут переупорядочены
  2. Заполнение будет добавлено только между элементами с различными выравниваниями или в конце структуры
  3. указатель на структуру указывает на ту же ячейку памяти, что и указатель на ее первый член
  4. каждый элемент выровнен в соответствии с его типом
  5. в структуре могут быть безымянные дыры, необходимые для выравнивания

Из этого я могу экстраполировать, что a и b не имеют отступов между ними. Однако возможно, что структура будет иметь отступ в конце. Я сомневаюсь в этом, поскольку он выровнен по словам в 32- и 64-разрядных системах. У кого-нибудь есть дополнительная информация по этому поводу?

Ответы [ 4 ]

10 голосов
/ 21 марта 2011

Реализация свободна для дополнения структур - между a и b могут быть неиспользованные байты.Гарантируется, что первый член не смещен относительно начала структуры.

Обычно вы управляете таким макетом с помощью специфической для компилятора прагмы, например:

#pragma pack(push)
#pragma pack(1)
struct TwoInt32s
{
  int32_t a;
  int32_t b;
};
#pragma pack(pop)
3 голосов
/ 21 марта 2011

malloc выделяет байты. Почему вы выбрали "2 * len"?

Вы можете просто использовать "sizeof":

int32_t *buffer = malloc(len * sizeof(TwoInt32s));
/* fill in the buffer */
write((struct TwoInt32s*)buffer, len);

и, как упоминал Эрик, было бы неплохо упаковать структуру.

2 голосов
/ 21 марта 2011

Безопаснее не приводить, а преобразовывать, т. Е. Создавать новый массив и заполнять его значениями, найденными в структуре, а затем уничтожать структуру.

0 голосов
/ 21 марта 2011

Вы можете размещать структуры, но обрабатывать их элементы как своего рода виртуальный массив:

struct TwoInt32s *buffer = malloc(len * sizeof *buffer);

#define BUFFER(i) (*((i)%2 ? &buffer[(i)/2].b : &buffer[(i)/2].a))

/* fill in the buffer, e.g. */
for (int i = 0; i < len * 2; i++)
    BUFFER(i) = i;

К сожалению, ни GCC, ни Clang в настоящее время не "получают" этот код.

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