Нет стандартного способа сделать это. Стандарт гласит, что заполнение может быть выполнено по усмотрению реализации. От C99 6.7.2.1 Structure and union specifiers
, пункт 12:
Каждый член не-битового поля структуры или объекта объединения выравнивается способом, определяемым реализацией, соответствующим его типу.
Сказав это, есть несколько вещей, которые вы можете попробовать.
Сначала вы уже со скидкой, используя #pragma
, пытаетесь убедить компилятор не упаковывать. В любом случае, это не портативно. Как и другие способы реализации, но вы должны проверить их, так как это может потребоваться, если вам действительно нужна эта возможность.
Второй - упорядочить поля в порядке возрастания, например, все типы long long
, за которыми следуют long
, затем все типы int
, short
и, наконец, char
. Это обычно работает, так как чаще всего для более крупных типов предъявляются более строгие требования к выравниванию. Опять не переносимо.
В-третьих, вы можете определить свои типы как char
массивы и привести адреса, чтобы гарантировать отсутствие заполнения. Но имейте в виду, что некоторые архитектуры будут замедляться, если переменные не выровнены должным образом, а другие будут с треском проваливаться (например, например, возникнет ошибка BUS и завершится ваш процесс).
Этот последний имеет какое-то дальнейшее объяснение. Допустим, у вас есть структура с полями в следующем порядке:
char C; // one byte
int I; // two bytes
long L; // four bytes
При заполнении вы можете получить следующие байты:
CxxxIIxxLLLL
где x
- отступ.
Однако, если вы определите свою структуру как:
typedef struct { char c[7]; } myType;
myType n;
вы получите:
CCCCCCC
Затем вы можете сделать что-то вроде:
int *pInt = &(n.c[1]);
int *pLng = &(n.c[3]);
int myInt = *pInt;
int myLong = *pLng;
чтобы дать вам:
CIILLLL
Опять же, к сожалению, не переносимый.
Все эти «решения» основаны на глубоких знаниях вашего компилятора и основных типов данных.