uint8 t vs unsigned char


в чем преимущество использования uint8_t over unsigned char в C?

Я знаю, что почти на каждой системе uint8_t Это просто typedef для unsigned char, так зачем же его использовать?

8 191

8 ответов:

он документирует ваше намерение - вы будете хранить небольшие числа, а не символ.

также это выглядит лучше, если вы используете другие typedefs, такие как uint16_t или int32_t.

просто чтобы быть педантичным, некоторые системы могут не иметь 8-битный тип. Согласно Википедия:

реализация требуется для определения целочисленных типов точной ширины для N = 8, 16, 32 или 64 тогда и только тогда, когда он имеет любой тип, который соответствует требованиям. Не требуется определять их для любых других N, даже если он поддерживает соответствующие типы.

так uint8_t не гарантируется существование, хотя это будет для всех платформ, где 8 бит = 1-байтовый. Некоторые встроенные платформы могут отличаться, но это становится очень редким. Некоторые системы могут определить char типы 16 бит, в этом случае, вероятно, не будет 8-битного типа.

кроме этой (незначительной) проблемы, @ответ Марка Рэнсома это лучший на мой взгляд. Используйте тот, который наиболее четко показывает, для чего вы используете данные.

кроме того, я предполагаю, что вы имели в виду uint8_t (стандартный typedef от C99, предоставленный в stdint.h заголовок), а не uint_8 (не частью какого-либо стандарта).

все дело в том, чтобы написать независимый от реализации код. unsigned char не гарантируется 8-битный тип. uint8_t есть.

как вы сказали, "почти каждая система".

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

по моему опыту есть два места, где мы хотим использовать uint8_t для обозначения 8 бит (и uint16_t и т. д.) и где мы можем иметь поля меньше 8 бит. Оба места, где пространство имеет значение, и мы часто должны смотреть на необработанный дамп данных при отладке и должны быть в состоянии быстро определить, что он представляет.

первое в протоколах РФ, особенно в узкополосных системах. В этой среде нам может потребоваться упаковать столько информации, сколько мы можем в один сообщение. Второй-во флэш-памяти, где у нас может быть очень ограниченное пространство (например, во встроенных системах). В обоих случаях мы можем использовать упакованную структуру данных, в которой компилятор будет заботиться о упаковке и распаковке для нас:

#pragma pack(1)
typedef struct {
  uint8_t    flag1:1;
  uint8_t    flag2:1;
  padding1   reserved:6;  /* not necessary but makes this struct more readable */
  uint32_t   sequence_no;
  uint8_t    data[8];
  uint32_t   crc32;
} s_mypacket __attribute__((packed));
#pragma pack()

какой метод вы используете, зависит от вашего компилятора. Также может потребоваться поддержка нескольких различных компиляторов с одинаковыми файлами заголовков. Это происходит во встроенных системах, где устройства и серверы могут быть совершенно разными - например, вы можете есть устройство ARM, которое взаимодействует с сервером x86 Linux.

есть несколько предостережений с использованием упакованных структур. Самая большая проблема заключается в том, что вы должны избегать разыменования адреса участника. В системах с выровненными словами mutibyte это может привести к несогласованному исключению - и coredump.

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

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

вот некоторые актуальные обсуждения:

pragma pack (1) ни _ _ атрибут__ ((выровнен (1))) работает

является ли GCC__attribute _ _ ((packed)) / #pragma pack небезопасным?

http://solidsmoke.blogspot.ca/2010/07/woes-of-structure-packing-pragma-pack.html

есть немного. С точки зрения переносимости, char не может быть меньше, чем 8 бит, и ничто не может быть меньше char, поэтому, если данная реализация C имеет беззнаковый 8-разрядный целочисленный тип, это будет char. Кроме того, он может не иметь его вообще, и в этот момент любой typedef трюки спорный.

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

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

почти в каждой системе я встречал uint8_t == unsigned char, но это не гарантируется стандартом C. Если вы пытаетесь написать переносимый код, и это так же важно, что размер памяти, использовать uint8_t. В противном случае использовать беззнаковый тип char.