Как использовать стандартные типы C99 для максимальной мобильности и эффективности на большинстве платформ?

Во-первых, вот что я понимаю и думаю, что верно для вопроса.

Используйте быстрые типы данных для отдельных переменных, таких как счетчики илиfor циклические индексы. Например:

#define LOOP_COUNT (100U)

uint_fast8_t index;
for(index = 0; index < LOOP_COUNT; index++){
    /* Do something */
}

Я полагаю, наиболее подходящий тип здесьuint_fast8_t посколькуindex никогда не может превышать 255, и это будет самая быстрая реализация для всех платформ. Если бы я использовалunsigned int вместо этого он будет быстрее на> = 16-битных платформах, но будет медленнее на <16-битных платформах, так какint минимум 16 бит по стандарту. Кроме того, если бы я использовалuint8_t это будет медленнее на> 8-битных платформах, так как компилятор добавляетAND 0xFF инструкция для проверки переполнения для каждого приращения (мой компилятор ARM7 делает это даже при полной скорости оптимизации).size_t также не вариант, так как он может быть больше, чем собственный целочисленный размер.

Плохая сторона (?) Этого, если ожидается переполнение для 8 битов, этого не произойдет. Программист должен проверить на переполнение вручную (как он / она должен ИМХО), что может привести к ошибочному коду, если он будет забыт. Кроме того, компилятор (и даже PC-Lint, к моему удивлению) не будет выдавать никаких предупреждений / проблем, если LOOP_COUNT «случайно» установлен на значение больше 255 на> 8-битных платформах, но предупреждение будет сгенерировано на 8-битной платформе, что уменьшит мобильность и внесет ошибки, но этого можно избежать с#if чеки.

Используйте как можно меньше типов данных, если использование памяти имеет значение, как в массивах или структурах. Например:

uint_least8_t array[100];

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

Наименьший тип также может страдать от проблем, с которыми сталкиваются быстрые типы, поскольку ширина переменных может изменяться на разных платформах в обоих случаях.

По возможности избегайте типов данных фиксированной ширины, поскольку они могут даже не существовать на некоторых платформах, кроме доступа к аппаратному регистру, отображения протокола связи и т. Д., Где нам необходимо знать точные биты переменной. Например:

typedef struct {
    uint8_t  flags;
    uint8_t  length;
    uint8_t  data[100];
    uint16_t crc;
} __attribute__((packed)) package_t;

Обычно__attribute__((packed)) (или что-то подобное) следует использовать, чтобы гарантировать, что для этих случаев не будет вставлено дополнение, так как это само по себе может быть проблемой.

Теперь, если мое понимание верно, я думаю, что наименьшее количество типов данных будет более вероятно использоваться в массивах или структурах, быстрые типы данных будут с большей вероятностью использоваться для отдельных переменных, а фиксированные типы данных вряд ли будут использоваться для достижения максимального портативность и эффективность. Но печатать «быстро» и «минимум» каждый раз не обнадеживает. Итак, я думаю о наборе типов следующим образом:

    typedef [u]intN_t       os_[u|s]exactN_t;
    typedef [u]int_fastN_t  os_[u|s]N_t;
    /* I couldn't come up with a better name */
    typedef [u]int_leastN_t os_[u|s]minN_t;
    /* These may change */
    typedef uint_least8_t   os_byte_t;
    typedef uint_least16_t  os_word_t;
    /* ... */
Первый и важный вопрос: верно ли мое понимание?Какой самый удобный и эффективный способ использовать стандартные типы C99 и как бы вы их объявили, если это не так?Имеет ли смысл мой набор типов или это может привести к ошибочному коду?

Также мне было бы приятно узнать, как и где вы используете стандартные типы C99.

Ответы на вопрос(0)

Ваш ответ на вопрос