Подтвердить что ты не робот

Должен ли буфер с байтами быть подписанным или без знака char buffer?

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

Спасибо.

4b9b3361

Ответ 1

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

Небольшое различие в том, как язык относится к нему. A огромная разница в том, как соглашение обрабатывает его.

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

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

Ответ 2

Если вы собираетесь хранить произвольные двоичные данные, вы должны использовать 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 для этих целей выглядит для меня неправильным решением.

Для получения дополнительной информации прочитайте this proposal, в котором содержится исправление для следующей версии стандарта C, которое в конечном итоге потребует signed char not также есть любые биты дополнений. Он уже включен в рабочий документ .

Ответ 3

Это зависит.

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

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

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

Ответ 4

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

Ответ 5

Вы должны использовать либо char, либо unsigned char, но никогда не подписываться char. Стандарт имеет следующий вид в 3.9/2

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

Ответ 6

Лучше определить его как unsigned char. Infact Win32 type BYTE определяется как unsigned char. Между этим нет разницы между C и С++.

Ответ 7

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

Ответ 8

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


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

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

VS

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


По этой причине я бы использовал uint8_t.

Ответ 9

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

Ответ 10

Должен и должен... Я склонен предпочитать unsigned, так как он чувствует себя более "сырым", менее привлекательным, чтобы сказать "эй, это просто кучка маленького ints", если я хотите подчеркнуть двоичную информацию данных.

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

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

Ответ 11

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

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

Ответ 12

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

Ответ 13

typedef char byte;

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

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

Ответ 14

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

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

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

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