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

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

Спасибо.

вопрос задан 17.03.2009
jackhab
6186 репутация

14 ответов


  • 47 рейтинг

    Если вы намереваетесь хранить произвольные двоичные данные, вы должны использовать unsigned char. Это единственный тип данных, который гарантированно не содержит битов заполнения в стандарте C. Каждый другой тип данных может содержать биты заполнения в своем объектном представлении (то есть тот, который содержит все биты объекта, а не только те, которые определяют значение). Состояние битов заполнения не определено и не используется для хранения значений. Таким образом, если вы читаете с использованием 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 битов - так что вы можете ожидать, что такое назначение будет в порядке - но не в пределах диапазон char, который составляет CHAR_MIN. , CHAR_MAX, такое преобразование переполняется и вызывает реализацию определенных результатов, в том числе повышение сигналов.

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

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

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

    ответ дан Johannes Schaub - litb, с репутацией 398434, 17.03.2009
  • 28 рейтинг

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

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

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

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

    ответ дан dan04, с репутацией 60687, 20.02.2011
  • 12 рейтинг

    Это зависит.

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

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

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

    ответ дан RBerteig, с репутацией 33461, 17.03.2009
  • 9 рейтинг

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

    ответ дан Pete Kirkham, с репутацией 42751, 17.03.2009
  • 5 рейтинг

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

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

    ответ дан Richard Corden, с репутацией 17845, 17.03.2009
  • 4 рейтинг

    Лучше определить его как неподписанный символ. Infact Win32 типа BYTE определяется как беззнаковый символ. Разницы между C & amp; C ++ между этим.

    ответ дан Naveen, с репутацией 50527, 17.03.2009
  • 3 рейтинг

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

    ответ дан MrEvil, с репутацией 2710, 17.03.2009
  • 2 рейтинг

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


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

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

    VS

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


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

    ответ дан Trevor Boyd Smith, с репутацией 6952, 17.03.2009
  • 0 рейтинг

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

    ответ дан pngaz, с репутацией 307, 17.03.2009
  • 0 рейтинг

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

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

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

    ответ дан unwind, с репутацией 312521, 17.03.2009
  • 0 рейтинг

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

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

    ответ дан schnaader, с репутацией 41128, 17.03.2009
  • 0 рейтинг

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

    ответ дан Gorpik, с репутацией 9105, 17.03.2009
  • -1 рейтинг

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

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

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

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

    ответ дан Darron, с репутацией 18701, 17.03.2009
  • -1 рейтинг
    typedef char byte;
    

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

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

    ответ дан Matt Cruikshank, с репутацией 2630, 17.03.2009