Организация структур
Для объединения нескольких переменных, относящихся к одной сущности, используют структуры. Может показаться, что расположение полей не имеет особого значения, однако это не так: плотность кода (англ. code density) можно улучшить простым перемешиванием полей, точнее, правильной упорядоченностью. Сравним две структуры:
struct {
char a;
int b;
char c;
short d;
} FIRST;
struct {
char a;
char c;
short d;
int b;
} SECOND;
Замерив размер функцией sizeof()
, мы увидим, что FIRST
занимает 12 байт, а размер SECOND
при том же содержании оказывается меньше — всего 8 байт.
Структура FIRST
в памяти:
1 | 2 | 3 | 4 |
---|---|---|---|
— | — | — | a[7:0] |
b[31:24] | b[23:16] | b[15:8] | b[7:0] |
— | c[7:0] | d[15:8] | d[7:0] |
Структура SECOND
в памяти:
1 | 2 | 3 | 4 |
---|---|---|---|
a[7:0] | c[7:0] | d[15:8] | d[7:0] |
b[31:24] | b[23:16] | b[15:8] | b[7:0] |
Помните, что размер слова — 32 бита, а процессор ARM может эффективно заполнять это пространство, используя специальные инструкции чтения или записи полуслова и байта. Другими словами, сортируйте переменные в структуре в порядке увеличения их размера: сначала 8-битные, затем 16-, 32- и 64-битные переменные, а уже после них массивы. Разрешить проблему можно по-другому, добавив атрибут __attribute__((packed))
перед названием типа (любой структуры).
// ...
} __attribute__((packed)) FIRST;
// sizeof(FIRST) == 8
Иногда, напротив, нужно быть уверенным, что структура занимает четное количество полуслов/слов в памяти. В таком случае нужно добавить aligned(x)
, где x
— степень двойки.
typedef enum {
uint8_t name[10];
} __attribute__((packed, aligned(2))) SETTINGS_t;
// sizeof(SETTINGS_t) == 10
typedef enum {
uint8_t name[10];
} __attribute__((packed, aligned(4))) SETTINGS_t;
// sizeof(SETTINGS_t) == 12