c структура с элементами массива нулевого размера - PullRequest
0 голосов
/ 03 октября 2018

Я столкнулся с некоторым синтаксисом в открытом исходном коде Android, который я не могу понять.Есть структура, которая выглядит примерно так:

    struct __attribute__((packed)) A
{
 uint8_t bla;
 uint8_t bla2;
 uint8_t someFixedSizeArr[20];
 uint8_t padded[0]; //Marks offset to padded data
 uint8_t someFixedSizeArr2[30];
 uint8_t transformed[0]; //Marks offset to transformed data
 int32_t length;
 uint8_t result[100];
};

Я не понимаю, что такое дополненные и преобразованные и как они работают.Позже ctor типа B (который оборачивает A) их не трогает, поэтому они не инициализируются при создании B, но позже на них ссылаются так:

memmove(&A.padded[padLength], &A.result[A.length], 30);

А также:

someFunc(A.transformed, 30, A.someFixedSizeArr);

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

Спасибовы

Ответы [ 2 ]

0 голосов
/ 03 октября 2018

Это так же, как выражено.

uint8_t transformed[0] для практических целей является «указателем» на массив с нулевыми элементами и ведет себя как любой другой результат a[n], включая то, что вы не можете получить доступ к более чем [n] элементов массива.

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

Обратите внимание на поле с именем length чуть ниже transformed;Скорее всего, это длина массива transformed.Чтобы получатель вычислял размер структуры, он считывал бы длину и вычислял размер преобразованного, чтобы определить размер структуры.(length*sizeof(uint8_t))

Вы можете думать о массивах нулевой длины как о указателе, содержимое которого встроено само по себе и очень похоже на гибкий элемент массива, однако ему не хватает безопасности (если вы могли бы назвать его безопасным)гибких членов массива.

Вы не предоставили достаточно кода, чтобы вникнуть в то, что может делать uint8_t padding[0], но это в сочетании с __attribute__((packed)) заставило бы меня поверить в то, что они сочли необходимым вручную управлять структурой памяти структуры, но опять же,соответствующий код отсутствует, чтобы вывести это.

0 голосов
/ 03 октября 2018

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

  • Объявление массива нулевого размера было нарушением ограничения (для этого требовалосьдиагностический) в ISO C 90 во всех контекстах: даже в качестве параметра функции, где объявленный идентификатор фактически является указателем, а не массивом вообще!

  • C99 добавил «гибкийэлемент массива »: последний элемент структуры может быть массивом нулевого размера:« В особом случае последний элемент структуры с более чем одним именованным элементом может иметь неполный тип массива; это называется гибким массивомmember.

  • В коде C90 "взлом структуры" реализован с использованием массива размера [1] в конце структуры. Некоторые компиляторы допускают ноль (например, GNU C, Iдумать) до C99.

мы должны использовать offsetof (type, last_member), чтобы исключить [1] из вычисления:

struct foo {
/* ... */
int array[ZERO_OR_ONE];
};

/* Correct in C99, if ZERO_OR_ONE is 0
 Incorrect in C90, (ZERO_OR_ONE can't be zero).  */
size_t foo_plus_3_elems = sizeof (struct foo) + 3 * sizeof(int);

/* Correct in C99 whether or not ZERO_OR_ONE is 0 or 1.
 Correct in C90 with ZERO_OR_ONE being 1. */
size_t foo_plus_3_elems = offsetof (struct foo, array) + 3 * sizeof(int);
  • Здесь «неправильный» означает, что мынемного больше памяти, чем необходимо, обычно без каких-либо недостатков.

  • «Правильно в C90» означает де-факто правильное, а не то, что это было четко определенное поведение."Все" делали это.

...