Вопрос 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. Почему это происходит?
Любые мысли..
Да - ваш расчет правильный. На вашей машине sizeof(int) == 4
, и int
должен быть выровнен по 4 байтам.
Вы можете узнать о прокладке, сложив вручную размеры базовых элементов и вычтя их из размера, сообщенного sizeof(). Вы можете предсказать величину набивки, если знаете требования к выравниванию на вашей машине. Обратите внимание, что некоторые машины достаточно требовательны и выдают ошибку SIGBUS при обращении к данным с неправильным выравниванием; другие машины более мягкие, но замедляют работу при обращении к данным с неправильным выравниванием (и они могут поддерживать '#pragma packed
' или что-то подобное). Часто базовый тип имеет размер, равный степени 2 (1, 2, 4, 8, 16), и такой n-байтовый тип должен быть выровнен по n-байтам. Также помните, что структуры должны быть заполнены так, чтобы в массиве структур все элементы были правильно выровнены. Это означает, что структура обычно заполняется до размера, кратного размеру самого строго выровненного члена структуры.
Как правило, лучше использовать первый вариант; он остается верным при изменении базового типа массива с 'foo' на 'foobar'. Макрос, который я обычно использую:
#define DIM(x) (sizeof(x)/sizeof(*(x)))
У других людей есть другие названия для той же базовой операции - и вы можете списать название, которое использую я, на загрязнение из тусклого и далекого прошлого и некоторое использование BASIC.
Как обычно, есть оговорки. Самое главное, вы не можете применить это к аргументам массива в функции или к динамически выделенному массиву (используя malloc()
и др. или new[]
); вы должны применить это к фактическому определению массива. Обычно значение является константой времени компиляции. Согласно C99, оно может быть оценено во время выполнения, если массив является VLA - массивом переменной длины.
Из-за того, как работает инициализация, когда у вас недостаточно скобок. Ваша структура 'foo' должна иметь два элемента. 10 и 20 выделяются в первую строку; 30 и неявный 0 поставляются во вторую строку. Следовательно, размер равен двум. Если поставить подстрочные скобки, то в массиве будет 3 элемента, первые компоненты которых имеют значения 10, 20, 30, а вторые - нули.
Чтобы узнать, сколько у вас заполнений, просто сложите sizeof () для каждого элемента структуры. , и вычтите эту сумму из sizeof () всей структуры.
Вы можете использовать offsetof (), чтобы точно узнать, где находится отступ в более сложных структурах. Это может помочь вам заполнить дыры, переставляя элементы, уменьшая размер структуры в целом.
Хорошей практикой является явное выравнивание элементов структуры, вручную вставляя элементы заполнения, чтобы каждый элемент гарантированно был «естественно выровнен». Вы можете повторно использовать эти элементы заполнения для получения полезных данных в будущем. Если вы когда-нибудь напишете библиотеку, для которой потребуется стабильный ABI, это будет обязательным методом.
Заполнение обычно связано с размером регистров на процессоре hist - в вашем случае у вас 32-разрядный процессор, поэтому «естественный» размер int составляет 4 байта. Процессору медленнее и труднее получить доступ к объемам памяти, меньшим этого размера, поэтому обычно предпочтительно выравнивать значения по 4-байтовым границам. Таким образом, размер структуры кратен 4 байтам. Большинство компиляторов позволяют изменять количество используемых отступов (например, с помощью "#pragma"), но это следует использовать только там, где объем памяти, занимаемый структурой, является абсолютно критическим.
«* foos» ссылается на первую запись в массиве foos. "foo" ссылается на тип (единственный экземпляр). Так что по сути они одинаковы. Я бы сам использовал sizeof (type) или sizeof (array [0]), поскольку * array легче неправильно прочитать.
В вашем первом примере вы неправильно инициализируете записи массива. В вашей структуре 2 члена, поэтому вы должны использовать {a, b} для инициализации каждого члена массива. Итак, вам нужна форма {{a, b}, {a, b}, {a, b}} для правильной инициализации записей.