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

Я часто работаю с библиотеками, которые используют символ при работе с байтами в C++. Альтернатива должна определить "Байт" как неподписанный символ, но что не стандарт они решили использовать. Я часто передаю байты от C# в C++ dlls и бросаю их для обугливания для работы с библиотекой.

При кастинге ints к символам или символам к другим простым типам, что является некоторыми побочными эффектами, которые могут произойти. А именно, когда это взломало код, что Вы продолжили работать и как Вы узнавали, что это было из-за символа, со знаком?

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

12
задан tvanfosson 3 February 2010 в 15:09
поделиться

8 ответов

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

#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, даже если a и b начинаются с тем же битовым шаблоном (заданы 8-битные символы, два дополнения и значения со знаком с использованием арифметического сдвига).

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

4
ответ дан 2 December 2019 в 22:51
поделиться

Меня укусила символьная подпись при написании алгоритмов поиска, которые использовали символы из текста в качестве индексов в деревьях состояний. У меня также были проблемы с расширением символов в более крупные типы, а знаковый бит распространяется, вызывая проблемы в других местах.

Я узнал об этом, когда начал получать странные результаты и ошибки сегментации, возникающие при поиске текстов, отличных от того, который я использовал во время начальной разработки (очевидно, символы со значениями> 127 или <0 будут вызывать это, и победил ' t обязательно должны присутствовать в ваших типичных текстовых файлах.

Всегда проверяйте наличие подписи переменной при работе с ней. Обычно теперь я делаю подписанные типы, если у меня нет веской причины в противном случае, выполняя приведение при необходимости. char в библиотеках, чтобы просто представить байт. Помните, что подписи char не определены (в отличие от других типов), вы должны уделить ему особое внимание и быть внимательными.

1
ответ дан 2 December 2019 в 22:51
поделиться

Спецификации языков C и C ++ определяют 3 типа данных для хранения символов: char , signed char и символ без знака . Последние 2 обсуждались в других ответах. Давайте посмотрим на тип char .

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

Таким образом, существует 3 версии типа данных char . Тип данных char хорошо подходит для хранения символов, но не подходит для арифметики на разных платформах и трансляторах, поскольку его подписи определяется реализацией.

0
ответ дан 2 December 2019 в 22:51
поделиться

Самые очевидные гетчи приходят тогда, когда при реализации протоколов или схем кодирования необходимо сравнить числовое значение char с шестнадцатеричной константой.

Например, при реализации telnet это может понадобиться.

// Check for IAC (hex FF) byte
if (ch == 0xFF)
{
    // ...

Или при тестировании для многобайтовых последовательностей UTF-8.

if (ch >= 0x80)
{
    // ...

К счастью, эти ошибки, как правило, не сохраняются до тех пор, пока даже самое поверхностное тестирование на платформе со знаком char должно их выявить. Их можно исправить, используя символьную константу, преобразовав числовую константу в char или преобразовав символ в неподписанный 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
2
ответ дан 2 December 2019 в 22:51
поделиться

Тот, который меня больше всего раздражает:

typedef char byte;

byte b = 12;

cout << b << endl;

Конечно, это косметика, но ...

1
ответ дан 2 December 2019 в 22:51
поделиться

При приведении целых чисел к символам или символов к другим простым типам

Критическим моментом является то, что преобразование значения со знаком из одного примитивного типа в другой (больший) тип не сохраняет битовый шаблон (при условии дополнения до двух). Знаковый символ с битовой комбинацией 0xff равен -1, а знаковый короткий с десятичным значением -1 равен 0xffff . Однако преобразование беззнакового char со значением 0xff в беззнаковое короткое приводит к 0x00ff . Поэтому всегда думайте о правильной подписи, прежде чем приводить к большему или меньшему типу данных. Никогда не переносите неподписанные данные в подписанных типах данных, если вам не нужно - если внешняя библиотека вынуждает вас сделать это, выполняйте преобразование как можно позже (или как можно раньше, если внешний код действует в качестве источника данных).

0
ответ дан 2 December 2019 в 22:51
поделиться

Вы потерпите неудачу при компиляции для нескольких платформ, потому что стандарт C ++ не определяет char как имеющий определенную «подписанность».

Поэтому GCC вводит параметры -fsigned-char и -funsigned-char для принудительного выполнения определенного поведения. Дополнительную информацию по этой теме можно найти, например, здесь .

РЕДАКТИРОВАТЬ:

Как вы просили привести примеры неработающего кода, существует множество возможностей взломать код, обрабатывающий двоичные данные. Например, для изображения вы обрабатываете 8-битные образцы звука (диапазон от -128 до 127) и хотите уменьшить громкость вдвое. А теперь представьте этот сценарий (в котором наивный программист предполагает 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);

Надеюсь, вам понравится этот пример ;-) Но, честно говоря, я никогда не сталкивался с такими проблемами, даже как новичок, насколько я помню ...

Надеюсь, этого ответа достаточно для вас, проголосовавших против. А как насчет короткого комментария?

0
ответ дан 2 December 2019 в 22:51
поделиться

Расширение знака. Первая версия моей функции кодирования URL выдавала строки вроде «% FFFFFFA3».

0
ответ дан 2 December 2019 в 22:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: