Структура заполнения в C - PullRequest
0 голосов
/ 01 августа 2009

Я читал об заполнении структуры в C: http://bytes.com/topic/c/answers/543879-what-structure-padding и написал этот код после статьи, что должно выводить размер «struct pad», например, 16 байт, а размер «struct pad2» должен быть 12. Я скомпилировал этот код с помощью gcc, с разными уровнями оптимизации, даже оператор sizeof () дает мне обоим по 16 байт. Почему это так?

Эта информация необходима мне из-за машин PS3, где важны границы байтов и использование полной передачи dma:

#include <stdio.h>
#include <stdlib.h>

struct pad
{
    char  c1;  // 1 byte
    short s1;  // 2 byte
    short s2;  // 2 byte
    char  c2;  // 1 byte
    long  l1;  // 4 byte
    char  c3;  // 1 byte
};

struct pad2
{
    long  l1;
    short s1;
    short s2;
    char  c1;
    char  c2;
    char  c3;
};

int main(void)
{
    struct pad P1;
    printf("%d\n", sizeof(P1));

    struct pad P2;
    printf("%d\n", sizeof(P2));

    return EXIT_SUCCESS;
}

Ответы [ 6 ]

4 голосов
/ 01 августа 2009

Есть две хитрости, которые могут быть использованы для решения этой проблемы

  1. Использование директивы #pragma pack (1) и затем #pragma pack (pop) Пример:

    #pragma pack(1)
    
    struct tight{           
       short element_1;       
       int *element_2;
    };
    #pragma pack(pop) 
    
  2. Чтобы проверить, совпадают ли размеры двух структур во время компиляции, используйте этот трюк

    char voidstr[(sizeof(struct1)==sizeof(struct2)) - 1]; //it will return error at compile time if this fail
    
3 голосов
/ 01 августа 2009

Каждая ваша структура включает в себя long, который, по-видимому, требует, чтобы ваша платформа находилась на четырехбайтовой границе. Структура должна быть, по крайней мере, такой же выровненной, как и ее наиболее выровненный элемент, поэтому она должна быть выровнена на 4 байта, а размер структуры должен быть кратным ее выравниванию в случае, если она входит в массив.

Для выравнивания long требуется дополнительное заполнение, поэтому наименьшее значение, кратное 4, равно 16.

Два совета:

  • Вы можете вычислить смещение поля l1 на

     printf("Offset of field %s is %d\n", "l1", offsetof(struct pad, l1);
    

    Чтобы получить макрос offsetof, вам понадобится #include <stddef.h> (спасибо caf!).

  • Если вы хотите упаковать данные максимально плотно, используйте unsigned char[4] вместо long и unsigned char[2] вместо short и выполните арифметическое преобразование.


РЕДАКТИРОВАТЬ :: sizeof(struct pad2) равно 12. Ваш код содержит ошибку; структура P2 объявлена ​​типа struct pad. Попробуйте это:

#define xx(T) printf("sizeof(" #T ") == %d\n", sizeof(T))
  xx(struct pad);
  xx(struct pad2);

P.S. Я определенно должен перестать пытаться отвечать на ТАК вопросы после полуночи.

1 голос
/ 29 июня 2010

Все CPU ожидают, что встроенные типы данных, такие как (int, float, char, double), сохраняются в памяти на их естественной границе, по адресу их длины. Поэтому заполнение структуры выполняется для более быстрого доступа к данным из памяти , Например, Если объявлено int, оно должно появиться в памяти по адресу, кратному 4, как

размер целого - 4 байта.

Аналогично для double, он находится в памяти, кратной 8.

Если память правильно выровнена, процессор может работать быстрее и эффективнее.

Для следующих примеров предположим:

Размер (int) = 4 байта

Sizeof (float) = 4 байта

Размер (символ) = 1 байт

Найти подробности по BoundsCheck

1 голос
/ 01 августа 2009
struct pad P1;
printf("%d\n", sizeof(P1));

struct pad P2;
printf("%d\n", sizeof(P2));

P1 и P2 имеют одинаковый тип "struct pad", может быть, вы хотите использовать "struct pad2" для P2.

1 голос
/ 01 августа 2009

Ваш код не показывает, что вы думаете, потому что оба P1 и P2 определены как экземпляры struct pad. struct pad2 никогда не используется.

Если я изменю определение P2 так, чтобы оно стало struct pad2, gcc действительно решит сделать его размером 12.

1 голос
/ 01 августа 2009

На PS3 не угадай. Используйте __attribute__((aligned (16))) или подобное. Это не только гарантирует, что начало структуры будет выровнено по правильной границе (если оно глобальное или статическое), но также добавит структуру к кратному указанному вами выравниванию.

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