Отключить заполнение структуры в C без использования прагмы - PullRequest
11 голосов
/ 29 ноября 2010

Как я могу отключить заполнение структуры в C без использования прагмы?

Ответы [ 6 ]

16 голосов
/ 29 ноября 2010

Нет стандартного способа сделать это. Стандарт гласит, что заполнение может быть выполнено по усмотрению реализации. От 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

Опять же, к сожалению, не переносимый.


Все эти «решения» основаны на глубоких знаниях вашего компилятора и основных типов данных.

3 голосов
/ 29 ноября 2010

Кроме параметров компилятора, таких как Pragma Pack, вы не можете, заполнение в стандарте C.

Вы всегда можете попытаться уменьшить заполнение, объявив наименьший тип, последний в структуре, как в:

struct _foo {
     int a;  /* No padding between a & b */
     short b;
} foo;

struct _bar {
     short b; /* 2 bytes of padding between a & b */
     int a;
} bar;

Примечание для реализаций, имеющих 4-байтовые границы

1 голос
/ 29 ноября 2010

На некоторых архитектурах сам ЦП будет возражать, если его попросят работать с смещенными данными.Чтобы обойти это, компилятор может генерировать несколько выровненных инструкций чтения или записи, сдвигать и разделять или объединять различные биты.Можно разумно ожидать, что он будет в 5 или 10 раз медленнее, чем согласованная обработка данных.Но Стандарт не требует, чтобы компиляторы были готовы к этому ... учитывая стоимость производительности, он просто не пользуется достаточным спросом.Компиляторы, которые поддерживают явный контроль над заполнением, предоставляют свои собственные прагмы именно потому, что прагмы зарезервированы для нестандартных функций.

Если вам нужно работать с незаполненными данными, подумайте над написанием собственных процедур доступа.Возможно, вы захотите поэкспериментировать с типами, которые требуют меньшего выравнивания (например, использовать char / int8_t), но все еще возможно, что, например, размер структур будет округлен до кратных 4, что сильно нарушит структуру упаковки, в этом случае вы 'Вам нужно будет реализовать собственный доступ ко всей области памяти.

0 голосов
/ 10 июня 2017

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

-> использовать __attribute__((packed)) за определением структуры.например,

struct node {
    char x;
    short y;
    int z;
} __attribute__((packed));

-> использовать флаг -fpack-struct при компиляции кода c.например,

$ gcc -fpack-struct -o tmp tmp.c

Надеюсь, это поможет.Спасибо.

0 голосов
/ 27 апреля 2014

Если вам действительно нужны структуры без заполнения: определите типы данных замены для short, int, long и т. Д., Используя структуры или классы, состоящие только из 8-битных байтов. Затем составьте свои структуры более высокого уровня, используя типы данных замены.

Перегрузка операторов C ++ очень удобна, но вы можете добиться того же эффекта в C, используя структуры вместо классов. Приведенные ниже реализации приведения и присваивания предполагают, что ЦП может обрабатывать смещенные 32-битные целые числа, но другие реализации могут работать с более строгими ЦП.

Вот пример кода:

#include <stdint.h>
#include <stdio.h>

class packable_int { public:

  int8_t b[4];

  operator int32_t () const       { return *(int32_t*) b; }
  void operator =  ( int32_t n )  { *(int32_t*) b = n; }

};

struct SA {
  int8_t   c;
  int32_t  n;
} sa;

struct SB {
  int8_t        c;
  packable_int  n;
} sb;

int main () {
  printf ( "sizeof sa  %d\n", sizeof sa );    // sizeof sa  8               
  printf ( "sizeof sb  %d\n", sizeof sb );    // sizeof sb  5               
  return 0;
}
0 голосов
/ 29 ноября 2010

Либо вы позволяете компилятору выполнять заполнение, либо говорите, что не следует использовать #pragma, либо вы просто используете несколько байтов, таких как массив символов, и вы сами строите все свои данные (сдвигая и добавляя байты). Это действительно неэффективно, но вы будете точно контролировать расположение байтов. Я делал это иногда, подготавливая сетевые пакеты вручную, но в большинстве случаев это плохая идея, даже если она стандартная.

...