Следует буфер байтов, которые будут подписаны или без знака буфер случайной работы?


если буфер байтов будут подписаны char или unsigned char или просто буфер случайной работы? Есть ли различия между C и c++?

спасибо.

14 53

14 ответов:

должен ли быть подписан буфер байтов char или unsigned char или просто Чаре буфер? Любые различия между C и C++?

незначительной разницы в том, как язык относится к нему. А огромный разница в том, как конгресс относится к нему.

  • char = ASCII (или UTF-8, но там знаковость мешает)текстовое сведения
  • unsigned char = byte
  • signed char = редко используется

и есть код использует о таком различии. Всего неделю или две назад я столкнулся с ошибкой, когда данные JPEG были повреждены, потому что они передавались в char* версия нашей функции base64 encode-которая "услужливо" заменила все недопустимые UTF-8 в "строке". Изменение на BYTE ака unsigned char было все, что нужно, чтобы исправить это.

если вы собираетесь хранить произвольные двоичные данные, вы должны использовать unsigned char. Это единственный тип данных, который гарантированно не имеет битов заполнения по стандарту C. Каждый другой тип данных может содержать биты заполнения в своем представлении объекта (то есть тот, который содержит все биты объекта, а не только те, которые определяют значение). Состояние битов заполнения не определено и не используется для хранения значений. Так что если Вы читаете с помощью char некоторые двоичные данные, вещи будут сокращены до диапазон значений char (путем интерпретации только битов значений), но все еще могут быть биты, которые просто игнорируются, но все еще существуют и читаются memcpy. Так же, как заполнение битов в реальных объектах структуры. Типа unsigned char гарантированно не содержит их. Это следует из 5.2.4.2.1/2 (C99 TC2, n1124 здесь):

если значение объекта типа char обрабатывается как целое число со знаком при использовании в выражение, значение CHAR_MIN должно быть таким же, как SCHAR_MIN и этот значение CHAR_MAX должно быть таким же, как SCHAR_MAX. В противном случае, значение CHAR_MIN должно быть 0, а значение CHAR_MAX должно быть таким же, как UCHAR_MAX. значение UCHAR_MAX равна 2^CHAR_BIT − 1

из последнего предложения следует, что не остается места для каких-либо битов заполнения. Если вы используете char как тип вашего буфера, у вас также есть проблема переполнения: присвоение любого значения явно одному такому элементу, который является в диапазоне 8 бит-так что вы можете ожидать, что такое назначение будет в порядке - но не в пределах диапазона a char, которая составляет CHAR_MIN..CHAR_MAX, такое преобразование переполняет и вызывает реализацию определенных результатов, включая повышение сигналов.

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

для строк, однако, тип данных выбора char, который будет понят строковыми и печатными функциями. Используя signed char для этих целей по-моему, не для меня.

для получения дополнительной информации, читайте:!--41-->this proposal, которые содержат исправления для следующей версии стандарта C, которая в конечном итоге потребует signed char не имеют каких-либо бит заполнения либо. Он уже включен в рабочая тетрадь.

Это зависит.

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

если буфер, предназначенный для хранения двоичных данных, то это зависит от того, как вы собираетесь его использовать. Например, если двоичные данные действительно упакованный массив образцов данных, которые подписаны 8-битными измерениями АЦП с фиксированной точкой, затем signed char будет лучше.

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

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

вы должны использовать char или unsigned char а не подпись Чара. Стандарт имеет следующее в 3.9 / 2

для любого объекта (кроме базового класса подобъекта) стручка тип Т, является ли объект имеет допустимое значение типа T, лежащее в основе байт (1.7), составляющие объект может быть скопированы в массив char или неподписанный символ.Если содержание массив char или unsigned char является скопированный назад в объект, объект должен впоследствии удерживать его исходное значение.

лучше определить его как число без знака типа char. Фактически байт с Win32 тип определяется как число без знака типа char. Нет никакой разницы между C и C++ между этим.

для максимальной переносимости всегда используйте символ без знака. Есть несколько случаев, когда это может вступить в игру. Сериализованные данные, совместно используемые в системах с различным типом endian, сразу же приходят на ум. При выполнении сдвига или битовой маскировки значения являются другими.

выбор int8_t vs uint8_t аналогичен тому, когда вы сравниваете ptr с NULL.


с точки зрения функциональности сравнение с NULL-это то же самое, что сравнение с 0, потому что NULL-это #define для 0.

но лично, с точки зрения стиля кодирования, я предпочитаю сравнивать свои указатели с NULL, потому что NULL #define означает человека, поддерживающего код, который вы проверяете на плохой указатель...

VS

когда кто-то видит сравнение с 0, это означает, что вы проверяете определенное значение.


по вышеуказанной причине я бы использовал uint8_t.

Если вы извлекаете элемент в более широкую переменную, он, конечно, будет расширен или нет.

должен и должен ... Я склонен предпочитаю без подписи, так как он чувствует себя более "сырым", менее привлекательным, чтобы сказать: "Эй, это просто куча маленьких ints", Если я хочу подчеркнуть двоичность данных.

Я не думаю, что я когда-либо использовал явный signed char для представления буфера байтов.

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

несколько лет назад у меня была проблема с консольным приложением C++, которое печатало цветные символы для значений ASCII выше 128, и это было решено путем переключения с char на unsigned char, но я думаю, что это было разрешимо при сохранении типа char.

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

вы действительно заботитесь? Если вы этого не сделаете, просто используйте значение по умолчанию (char) и не загромождайте свой код неважным вопросом. В противном случае будущие сопровождающие будут задаваться вопросом, почему вы использовали signed (или unsigned). Сделайте их жизнь проще.

Если вы лжете компилятору, он накажет вас.

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

однако, если вам нужно работать с содержимым буфера, то правильное объявление типа сделает ваш код проще. Нет" int val = buf[i] & 0xff; " ерунда.

Итак, подумайте о том, что данные на самом деле и как нужно использовать его.

typedef char byte;

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

Я знаю, что это немного глупо, но это делает ваш код читать 100%, как задумано.