размер структуры отличается от версии typedef? - PullRequest
1 голос
/ 06 мая 2010

В моем коде есть следующее объявление структуры и typedef:

struct blockHeaderStruct {
    bool allocated;
    unsigned int length;
};
typedef struct blockHeaderStruct blockHeader;

Когда я делаю sizeof(blockheader), я получаю обратно 4 байта, но когда я sizeof(struct blockHeaderStruct), я получаю 8 байтов.

Почему это происходит? Почему я не получаю 5 назад?

Ответы [ 6 ]

4 голосов
/ 06 мая 2010

Во-первых, вы не можете сделать sizeof(blockHeaderStruct). Это просто не скомпилируется. То, что вы можете сделать, это sizeof(struct blockHeaderStruct), что действительно может дать вам 8 байтов в результате.

Во-вторых, получить другой результат от sizeof(blockheader) крайне маловероятно. Судя по вашей ссылке на sizeof(blockHeaderStruct) (которая, опять же, даже не скомпилируется), ваше описание проблемы является неточным. Присмотритесь к тому, что вы действительно делаете. Скорее всего, вы берете sizeof типа указателя (который дает вам 4), а не типа структуры.

В любом случае, попробуйте опубликовать реальный код.

3 голосов
/ 06 мая 2010

Глядя на определение вашей структуры, у вас есть 1-байтовое значение, за которым следует 4-байтовое целое число. Это целое число должно быть расположено на 4-байтовой границе, что заставит компилятор вставлять 3-байтовое заполнение после вашего 1-байтового bool. Что делает размер структуры до 8 байт. Чтобы избежать этого, вы можете изменить порядок элементов в структуре.

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

1 голос
/ 06 мая 2010

Наиболее вероятным сценарием является то, что вы на самом деле смотрите на размер указателя, а не struct, в 32-разрядной системе.

Однако int может быть 2 байта (16 бит). В этом случае ожидаемый размер структуры составляет 4:

  • 2 байта для int
  • 1 байт для bool
  • округлить до следующего кратного 2, потому что размер структуры обычно округляется до кратного размера его самого большого примитивного члена.

Ничто не может объяснить sizeof(blockHeaderStruct) != sizeof(struct blockHeader), хотя, учитывая, что typedef. Это совершенно невозможно.

0 голосов
/ 06 мая 2010

Распределение структур обычно происходит на границе 4 байта. То есть компилятор будет дополнять типы данных в структуре до 4-байтовой границы, прежде чем начинать со следующего типа данных. Учитывая, что это c ++ (bool имеет размер 1), а не c (bool должен быть #define как-то)

    struct blockHeaderStruct {
       bool allocated;         // 1 byte followed by 3 pad bytes
       unsigned int length;    // 4 bytes
    };
    typedef struct blockHeaderStruct blockHeader;
    typedef struct blockHeaderStruct *blockHeaderPtr;

Результатом операции sizeof будет:

sizeof(blockHeader) == 8
sizeof(struct blockHeader) == 8
sizeof(blockHeaderPtr) == 4

(Примечание: последняя запись будет 8 для 64-битный компилятор. )

Не должно быть разницы в размерах между первыми двумя строками кода. Определение типа просто присваивает псевдоним существующему типу. Третий - это размер указателя, который составляет 4 байта на 32-битной машине и 8 байтов на 64-битной машине.


Чтобы это исправить, просто примените директиву #pragma pack, прежде чем определить структуру. Это заставляет компилятор упаковать на указанной границе. Обычно устанавливается как 1,2 или 4 (хотя 4 обычно является значением по умолчанию и не требует установки).

#include <stddef.h>
#include <stdio.h>

#pragma pack(1)
struct blockHeaderStruct {
    bool allocated;
    unsigned int length;
};
typedef struct blockHeaderStruct blockHeader;

int main()
{
    printf("sizeof(blockHeader) == %li\n", sizeof(blockHeader));
    printf("sizeof(struct blockHeader) == %li\n", sizeof(struct blockHeaderStruct));

    return 0;
}

Скомпилировано с g ++ (Ubuntu 4.4.1-4ubuntu9) 4.4.1

Результаты:

sizeof(blockHeader) == 5  
sizeof(structblockHeader) == 5

Вам обычно не нужна эта директива. Просто не забудьте упаковать свои структуры эффективно. Группируйте меньшие типы данных вместе. Не чередуйте 4-байтовые типы данных и 4-байтовые типы данных, так как ваши структуры будут в основном неиспользованным пространством. Это может вызвать ненужную пропускную способность для приложений, связанных с сетью.

0 голосов
/ 06 мая 2010

Я скопировал этот фрагмент прямо из моего исходного файла.

OK.

Когда я делаю sizeof (blockheader), я получаю значение 4 байта назад

Похоже, что blockheader где-то определен как typedef и его тип занимает 4 байта, или его тип требует выравнивания 4 байтов.

Если вы попробуете sizeof (blockHeader), вы получите ваш тип.

когда я делаю sizeof (blockHeaderStruct), я получить 8 байтов.

Причина, по которой выравнивание имеет значение, заключается в том, что если вам нужен массив blockHeaders, вы можете вычислить, сколько памяти вам нужно. Или, если у вас есть массив и вам нужно вычислить, сколько памяти скопировать, вы можете вычислить его.

Если вы хотите выровнять все члены структуры по адресам, кратным 1 вместо 4 или вместо значений по умолчанию вашего компилятора, ваш компилятор может предложить #pragma для этого. Тогда вы сэкономите память, но доступ к ней может быть медленнее, чтобы получить доступ к невыровненным данным.

0 голосов
/ 06 мая 2010

Некоторые компиляторы оптимизируют, чтобы всегда распределять данные по степеням 2 (4 остается 4, но 5 округляется до 8).

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