Худшие побочные эффекты от подписания Чарс. (Объяснение влияния подписания на Chars и Chasts)

StackOverflow https://stackoverflow.com/questions/2192880

Вопрос

Я часто работаю с библиотеками, которые используют 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».

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top