Вопросы на использованиях sizeof

Вопрос 1

У меня есть структура как,

struct foo
{
    int a;
    char c;
};

Когда я говорю sizeof(foo), Я добираюсь 8 на моей машине. Согласно моему пониманию, 4 байта для интервала, 1 байт для символа и 3 байта для дополнения. Это корректно? Учитывая структуру как вышеупомянутое, как я узнаю, сколько байтов будет добавлено как дополнение?

Вопрос 2

Я знаю это sizeof может использоваться для вычисления размера массива. Главным образом я видел использование как (foos массив foo)

sizeof(foos)/sizeof(*foos)

Но я нашел, что следующее также даст тот же результат.

sizeof(foos) / sizeof(foo)

Есть ли какое-либо различие в этих двух? Какой предпочтен?

Вопрос 3

Рассмотрите следующее утверждение.

foo foos[] = {10,20,30};

Когда я делаю sizeof(foos) / sizeof(*foos), это дает 2. Но массив имеет 3 элемента. Если я изменяю оператор на

foo foos[] = {{10},{20},{30}};

это дает корректный результат 3. Почему это происходит?

Любые мысли..

5
задан Jonathan Leffler 29 March 2010 в 05:52
поделиться

3 ответа

Ответ 1

Да - ваш расчет правильный. На вашей машине sizeof(int) == 4, и int должен быть выровнен по 4 байтам.

Вы можете узнать о прокладке, сложив вручную размеры базовых элементов и вычтя их из размера, сообщенного sizeof(). Вы можете предсказать величину набивки, если знаете требования к выравниванию на вашей машине. Обратите внимание, что некоторые машины достаточно требовательны и выдают ошибку SIGBUS при обращении к данным с неправильным выравниванием; другие машины более мягкие, но замедляют работу при обращении к данным с неправильным выравниванием (и они могут поддерживать '#pragma packed' или что-то подобное). Часто базовый тип имеет размер, равный степени 2 (1, 2, 4, 8, 16), и такой n-байтовый тип должен быть выровнен по n-байтам. Также помните, что структуры должны быть заполнены так, чтобы в массиве структур все элементы были правильно выровнены. Это означает, что структура обычно заполняется до размера, кратного размеру самого строго выровненного члена структуры.

Ответ 2

Как правило, лучше использовать первый вариант; он остается верным при изменении базового типа массива с 'foo' на 'foobar'. Макрос, который я обычно использую:

#define DIM(x) (sizeof(x)/sizeof(*(x)))

У других людей есть другие названия для той же базовой операции - и вы можете списать название, которое использую я, на загрязнение из тусклого и далекого прошлого и некоторое использование BASIC.

Как обычно, есть оговорки. Самое главное, вы не можете применить это к аргументам массива в функции или к динамически выделенному массиву (используя malloc() и др. или new[]); вы должны применить это к фактическому определению массива. Обычно значение является константой времени компиляции. Согласно C99, оно может быть оценено во время выполнения, если массив является VLA - массивом переменной длины.

Ответ 3

Из-за того, как работает инициализация, когда у вас недостаточно скобок. Ваша структура 'foo' должна иметь два элемента. 10 и 20 выделяются в первую строку; 30 и неявный 0 поставляются во вторую строку. Следовательно, размер равен двум. Если поставить подстрочные скобки, то в массиве будет 3 элемента, первые компоненты которых имеют значения 10, 20, 30, а вторые - нули.

21
ответ дан 18 December 2019 в 06:11
поделиться

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

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

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

2
ответ дан 18 December 2019 в 06:11
поделиться
  1. Заполнение обычно связано с размером регистров на процессоре hist - в вашем случае у вас 32-разрядный процессор, поэтому «естественный» размер int составляет 4 байта. Процессору медленнее и труднее получить доступ к объемам памяти, меньшим этого размера, поэтому обычно предпочтительно выравнивать значения по 4-байтовым границам. Таким образом, размер структуры кратен 4 байтам. Большинство компиляторов позволяют изменять количество используемых отступов (например, с помощью "#pragma"), но это следует использовать только там, где объем памяти, занимаемый структурой, является абсолютно критическим.

  2. «* foos» ссылается на первую запись в массиве foos. "foo" ссылается на тип (единственный экземпляр). Так что по сути они одинаковы. Я бы сам использовал sizeof (type) или sizeof (array [0]), поскольку * array легче неправильно прочитать.

  3. В вашем первом примере вы неправильно инициализируете записи массива. В вашей структуре 2 члена, поэтому вы должны использовать {a, b} для инициализации каждого члена массива. Итак, вам нужна форма {{a, b}, {a, b}, {a, b}} для правильной инициализации записей.

3
ответ дан 18 December 2019 в 06:11
поделиться