Организация структур

Для объединения нескольких переменных, относящихся к одной сущности, используют структуры. Может показаться, что расположение полей не имеет особого значения, однако это не так: плотность кода (англ. 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 в памяти:

1234
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 в памяти:

1234
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

Изменено:

Эффективный код для Cortex-M: 3 комментария

  1. >Вопрос 48. Какой тип целочисленной переменной лучше всего СПОЛЬЗОВАТЬ в микроконтроллере PIC24 и почему?

  2. Здравствуйте.
    Мучаю STM32F030F4P6 и изучаю вашу книгу.
    Замерял сегодня скорость выполнения вышеприведённых циклов на разных оптимизациях кода O1 O2 O3.
    И у меня получилось что цикл
    for (i = 0; i < 1000000; i++) {} выполняется на любой оптимизации за 4800 микросекунд
    цикл for ( i = 1000000; i != 0; i—){} выполняется за 4800 микросек. только на оптимизации O1 . При оптимизации O2 и O3 он выполняется за 10800 микросекунд.
    цикл
    n = 1000000;
    do {
    // code here
    } while (—n != 0); на любой оптимизации выполняется за 10800 микросекунд

    может это связано с компиляцией и оптимизацией именно для данного чипа.
    но лучше я буду писать for (i = 0; i < 1000000; i++){}

  3. Взял осциллограф и всё перепроверил. Оказалось что у меня таймер переполнялся.
    Думаю что мои коменты публиковать не нужно )

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.