2009-03-17 3 views

ответ

26

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

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

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

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

+5

Итак, почему C++ iostreams используют 'char *' вместо 'unsigned char *' для представления буферов данных при чтении и записи двоичных потоков через методы 'read' и' write'? : P – BarbaraKwarc

+1

подписанный символ не так уж редко. В JNI (собственный интерфейс Java, NDK 14.1) подписанный символ определяется как jbyte. – r0ng

+3

wtf делает java, котор нужно сделать с этим (тьфу) – developerbmw

0

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

0

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

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

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

+1

Проблема в том, что вы не можете использовать символ без его продвижения. (char) 0xFF! = (unsigned char) 0xFF. Байты одинаковы, но они не сравниваются. –

4

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

+1

Использование конкретного случая (Win32) для доказательства общего утверждения - не лучшая идея. – BarbaraKwarc

0

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

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

12

Это зависит.

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

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

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

0

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

+5

Я не согласен. Если я столкнулся с массивом (подписанных) символов, я мог бы подумать, что он каким-то образом хранит текстовые данные. –

+1

Согласен с Dave VdE – dcw

+1

И почему массив unsigned char не может содержать текстовые данные? Обычная стандартная подпись по умолчанию отличается между архитектурами, но подписи libc строковых функций все те же. –

9

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

+0

Я прошел через это, и это звучит неплохо в теории, но это создает массу проблем, если вы передадите эти данные стандартным функциям C или POSIX (чтение/запись файлов/сокетов). –

+4

POSIX чтение/запись берут пустоту * буфер. Функции POSIX, которые ожидают char * (например, аргумент path для open()), ожидают строку, а не байтовый буфер. –

3

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

5

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

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

47

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

Если значение объекта типа полукокса трактуется как целое число, при использовании в качестве выражения, значение 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 также отсутствующих дополняющих битов. Он уже включен в working paper.

+0

B-but C99 6.2.6.2 говорит, что «подписанный символ не имеет битов заполнения» – Ivan

+7

Забудьте C. '[C++ 11: 3.9.1/1]:' [..] _A char, подписанный символ и unsigned char занимают одинаковое количество хранения и имеют одинаковые требования к выравниванию (3.11); то есть они имеют одно и то же представление объекта. Для типов символов все биты представления объекта участвуют в представлении значений ._ [..] Не означает ли это, что у всех трех типов символов есть, по крайней мере, _same_ padding? И я интерпретирую это далее, чтобы означать, что ни у кого из них нет. –

+0

(см. Http://stackoverflow.com/a/21176278/560648) –

2

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


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

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

VS

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


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

-1

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

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

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

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

0
typedef char byte; 

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

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

+3

Это не ** очевидно для программистов Windows, которые используются для 'typedef unsigned char BYTE'. – dan04

+0

Как это отвечает на вопрос? –

+3

В своем домене он называет его «буфером байтов». Большинство ответов говорят о том, что отличается от доступных вариантов. Я обратился к объяснению: «Если вы ссылаетесь на него как на« байты », может быть, лучше всего напечатать его таким образом». 23 человека Упомянули это как интересный вопрос, и 12 человек ЗНАЛИ это - это шокирует. Я соглашусь, что мой пост не пытается ответить на вопрос пользователя, но я также буду утверждать, что другие ответы здесь игнорируют аспект разработки программного обеспечения, который я пытался осветить: как назвать типы вещей. –

Смежные вопросы