Худшие побочные эффекты от подписания Чарс. (Объяснение влияния подписания на Chars и Chasts)
-
25-09-2019 - |
Вопрос
Я часто работаю с библиотеками, которые используют CHAR при работе с байтами в C ++. Альтернатива состоит в том, чтобы определить «байт» как не подписанный символ, но не стандарт, который они решили использовать. Я часто пропускаю байты из C # в DLL C ++ и бросил их, чтобы сработать с библиотекой.
При отливках INT MAT CHARS или CHARS к другим простым типам, каковы некоторые из побочных эффектов, которые могут возникнуть. В частности, когда имеет этот сломанный код, на котором вы работали, и как вы узнали, что это было из-за подписания Char?
Везло, что я не столкнулся с этим в моем коде, использовал Char подписанный литейный трюк обратно в встроенные системы в школе. Я ищу лучше понять проблему, так как я чувствую, это имеет отношение к работе, которую я делаю.
Решение
Один важный риск - это если вам нужно перенести байты. Подписанный символ хранит подписание при праве смещенной, тогда как не подписанный символ не. Вот небольшая тестовая программа:
#include <stdio.h>
int main (void)
{
signed char a = -1;
unsigned char b = 255;
printf("%d\n%d\n", a >> 1, b >> 1);
return 0;
}
Он должен распечатать -1 и 127, хотя и B и B начнет с одного и того же битового шаблона (учитывая 8-битные символы, два набора и подписанные значения с использованием арифметической смены).
Короче говоря, вы не можете полагаться на сдвиг, работающий идентично для подписанных и беззнаковных символов, поэтому, если вам нужна портативность, используйте unsigned char
скорее, чем char
или signed char
.
Другие советы
Наиболее очевидными Gotchas приходят, когда вам нужно сравнить числовое значение char
с шестнадцатеричной постоянной при реализации протоколов или схем кодирования.
Например, при реализации Telnet вы можете сделать это.
// Check for IAC (hex FF) byte
if (ch == 0xFF)
{
// ...
Или при тестировании для многобайтовых последовательностей UTF-8.
if (ch >= 0x80)
{
// ...
К счастью, эти ошибки обычно не выживают очень долго, как даже самые белые тестирования на платформе с подписанным char
следует раскрыть их. Они могут быть закреплены с помощью константы символов, преобразуя числовую постоянную в char
или преобразование персонажа в unsigned char
до того, как оператор сравнения способствует как к int
. Отказ Преобразование char
непосредственно к АН unsigned
Не будет работать, хотя.
if (ch == '\xff') // OK
if ((unsigned char)ch == 0xff) // OK, so long as char has 8-bits
if (ch == (char)0xff) // Usually OK, relies on implementation defined behaviour
if ((unsigned)ch == 0xff) // still wrong
Я был укушен подписью CAR в написании алгоритмов поиска, которые использовали символы из текста в качестве показателей в штате деревьев. У меня также имели это вызвать проблемы при расширении персонажей в более крупные типы, а подписанный бит распространяется, вызывая проблемы в другом месте.
Я выяснил, когда я начал получать причудливые результаты, и SegFaults, возникающие из поиска текстов, кроме того, что я использовал во время первоначального развития (очевидно, персонажи со значениями> 127 или <0 собираются вызвать это, и не обязательно будет присутствует в ваших типичных текстовых файлах.
Всегда проверяйте подпись переменной при работе с ней. Как правило, теперь я делаю типы, подписанные, если у меня нет веской причины иначе, кастинг при необходимости. Это хорошо вписывается в повсеместное использование char
В библиотеках просто представляют байт. Имейте в виду, что подпись char
Не определяется (в отличие от других типов), вы должны дать ему особое лечение и быть вспомнительно.
Тот, который больше всего раздражает меня:
typedef char byte;
byte b = 12;
cout << b << endl;
Конечно, это косметика, но Arrr ...
При отливании ints rams или rams к другим простым типам
Критическая точка состоит в том, что отливка подписанного значения из одного примитивного типа на другой (более крупный) тип не сохраняет шаблон бита (при условии, что дополнение двух). Подписанный символ с битовой шаблон 0xff
IS -1, в то время как подписанный короткий с десятичным значением -1 0xffff
. Отказ Разбивка без знака с ценностью 0xff
Однако до беззнаков, однако, урожайность 0x00ff
. Отказ Следовательно, всегда думайте о правильной подписании, прежде чем попечить на более крупный или меньший тип данных. Никогда не носите данные без знака в подписанных типах данных, если вам не нужно - Если внешняя библиотека заставляет вас сделать, выполните позже преобразование (или как можно раньше, если внешний код действует как источник данных).
Спецификации языка C и C ++ определяют 3 типа данных для удержания символов: char
, signed char
а также unsigned char
. Отказ Последние 2 обсуждались в других ответах. Давайте посмотрим на char
тип.
Стандартные (ы) говорят, что char
тип данных мая подписаться или без знаки и является решением реализации. Это означает, что некоторые компиляторы или версии компиляторов могут реализовать char
по-другому. Последствие в том, что char
Тип данных не способствует арифметическим или логическим операциям. Для арифметических и логических операций, signed
а также unsigned
версии char
будет работать нормально.
Таким образом, есть 3 версии char
тип данных. То char
Тип данных хорошо выполняет для удержания символов, но не подходит для арифметики по платформам и переводчикам, так как это подпись Определена реализация.
Вы не пройдете сжаты при компиляции нескольких платформ, потому что стандарт C ++ не определяет char
быть определенной «подписания».
Поэтому GCC вводит -fsigned-char
а также -funsigned-char
варианты форсирования определенного поведения. Больше на этой теме можно найти здесь, Например.
РЕДАКТИРОВАТЬ:
Когда вы просили примеры сломанного кода, существует множество возможностей разбивания кода, который обрабатывает двоичные данные. Например, изображение вы обрабатываете 8-битные образцы аудио (диапазон -128-127), и вы хотите Halven том. Теперь представьте этот сценарий (в котором наивный программист предполагает char == signed char
):
char sampleIn;
// If the sample is -1 (= almost silent), and the compiler treats char as unsigned,
// then the value of 'sampleIn' will be 255
read_one_byte_sample(&sampleIn);
// Ok, halven the volume. The value will be 127!
char sampleOut = sampleOut / 2;
// And write the processed sample to the output file, for example.
// (unsigned char)127 has the exact same bit pattern as (signed char)127,
// so this will write a sample with the loudest volume!!
write_one_byte_sample_to_output_file(&sampleOut);
Я надеюсь, вам понравится этот пример ;-) Но быть честным, я никогда не совсем не сталкивался с такими проблемами, а не как новичка, насколько я могу вспомнить ...
Надеюсь, что этот ответ достаточно для вас. Как насчет короткого комментария?
Расширение знака. Первая версия моей функции кодирования URL-кодирования производила строки, такие как «% FFFFFA3».