Могут ли массивы C содержать дополнения между элементами?

StackOverflow https://stackoverflow.com/questions/1066681

  •  21-08-2019
  •  | 
  •  

Вопрос

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

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

Итак, в коде слух такой:

{
    // Given this:
    struct { int values[20]; } foo;
    int values[20];

    // This may be true:
    sizeof(values) != sizeof(foo.values);
}

Я почти уверен, что sizeof(values) всегда будет равен sizeof(foo.values).Однако мне не удалось найти в стандарте C (в частности, C99) ничего, что явно подтверждало бы или опровергало это.

Кто-нибудь знает, рассматривается ли этот слух в каком-либо стандарте C?

редактировать:Я понимаю, что между концом массива может быть заполнение. foo.values и конец структуры foo и что стандарт гласит, что между началом foo и начало foo.values.Однако есть ли у кого-нибудь цитата из или ссылка на стандарт, в котором говорится, что между элементами нет отступов foo.values?

Это было полезно?

Решение

Нет, между элементами массива никогда не будет заполнения.Это специально не допускается.Стандарт C99 называет типы массивов: «Тип массива описывает непрерывно выделенный непустой набор объектов...».Напротив, структура выделяется «последовательно», а не «непрерывно».

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

Другие советы

Здесь осторожно.Заполнение может быть добавлено в конце структуры, но не будет добавлено между элементами массива, как вы указываете в своем вопросе.Массивы всегда будут ссылаться на непрерывную память, хотя в массиве структур к каждому элементу может быть добавлено дополнение как часть самой структуры.

В вашем примере values и foo.values массивы будут иметь одинаковый размер.Любое дополнение будет частью структуры. foo вместо.

Вот объяснение относительно почему структуре может потребоваться заполнение между ее членами или даже после последнего члена, и почему массив не делает этого:

Различные типы могут иметь разные требования к выравниванию.Некоторые типы необходимо выравнивать по границам слов, другие — по двойным или даже четверным границам слов.Для этого структура может содержать байты заполнения между ее членами.Завершающие байты заполнения могут потребоваться, поскольку ячейка памяти непосредственно за структурой также должна соответствовать требованиям выравнивания структуры, т. е. если bar имеет тип struct foo *, затем

(struct foo *)((char *)bar + sizeof(struct foo))

дает действительный указатель на struct foo (т.е. не выходит из строя из-за несоосности).

Поскольку каждый «член» массива имеет одинаковые требования к выравниванию, нет смысла вводить дополнение.Это справедливо и для массивов, содержащихся в структурах:Если первый элемент массива выровнен правильно, то же самое справедливо и для всех последующих элементов.

Да, типа того.Переменные часто выравниваются по некоторой границе, в зависимости от переменной.Возьмем, к примеру, следующее:

typedef struct
{
    double d;
    char c;
} a_type_t;

double и char имеют размер 8 и 1 байт в моей системе соответственно.Всего 9.Однако эта структура будет иметь размер 16 байт, так что двойные значения всегда будут выровнены по 8 байтам.Если бы я просто использовал целые числа, символы и т. д., то выравнивание могло бы быть 1, 2, 4 или 8.

Для некоторого типа Т sizeof(T) может быть равным или не равным sizeof(T.a) + sizeof(T.b) + sizeof(T.c) ... и т. д.

Как правило, это полностью зависит от компилятора и архитектуры.На практике это никогда не имеет значения.

Учитывать:

struct {
  short s;
  int i;
} s;

Предполагая, что шорты имеют 16-битную версию, а вы используете 32-битную версию, размер будет вероятно быть 8 байт, поскольку каждый член структуры имеет тенденцию выравниваться по границе слова (в данном случае 32-битного).Я говорю «вероятно», потому что это поведение, специфичное для реализации, которое можно изменить с помощью флагов компилятора и тому подобного.

Стоит подчеркнуть, что это поведение реализации, которое не обязательно определяется стандартом C.Очень похоже на размер коротких, целых и длинных чисел (стандарт C просто говорит, что короткие не будут больше целых, а длинные не будут меньше целых, что может в конечном итоге получиться как 16/32/32, 16/32/64). , 32/32/64 или ряд других конфигураций).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top