Что происходит на фоне приведения типа без знака к целочисленному типу? - PullRequest
2 голосов
/ 07 июня 2011

Сегодня я получил странное поведение от блока переключателей, в частности, я читал байт из файла и сравнивал его с определенными шестнадцатеричными значениями (проблема с кодировкой текстового файла, ничего страшного).Код выглядел примерно так:

char BOM[3] = {0};
b_error = ReadFile (iNCfile, BOM, 3, &lpNumberOfBytesRead, NULL); 

switch ( BOM[0] ) {
case 0xef: {
    // Byte Order Marker Potentially Indicates UTF-8
    if ( ( BOM[1] == 0xBB ) && ( BOM[2] == 0xBF ) ) {
        iNCfileEncoding = UTF8;
    }
    break;
           }
}

Что не сработало, хотя отладка выглядела нормально.Я понял, что переключатель продвигает значения в целые числа, и как только он щелкнул, я смог найти соответствие, используя 0xffffffef в выражении case.Конечно, правильное решение состояло в том, чтобы сделать BOM [] без знака, и теперь все продвигается и сравнивается, как и ожидалось.

Может кто-нибудь кратко объяснить, что происходило в продвижении char -> int, которое производило 0xffffffef вместо 0x000000ef?

Ответы [ 5 ]

3 голосов
/ 07 июня 2011

char должен быть подписан на вашей платформе, и вы видите расширение подписи .

3 голосов
/ 07 июня 2011

Знак вашего (подписанного) символа был расширен, чтобы сформировать подписанный int. Это связано с тем, что подписанные значения хранятся в двоичном формате.

Пример

1 в двоичном коде = 00000001

1 в двоичном формате int = 00000000 00000000 00000000 00000001

-1 в двоичном коде = 11111111

-1 в двоичном формате int НЕ 00000000 00000000 00000000 11111111, но 11111111 11111111 11111111 11111111

если вы преобразуете обратно в десятичное, вы должны знать заранее, имеете ли вы дело со значениями со знаком или без знака, потому что 11111111 может быть -1 в знаке и 255 в без знака.

2 голосов
/ 07 июня 2011

Что еще не было сказано (как я печатаю, так или иначе), так это то, что не определено, поется ли char или нет. В вашем случае - как было сказано - char подписан, поэтому любое значение ASCII выше 127 будет интерпретировано как отрицательное.

1 голос
/ 07 июня 2011

"Может кто-нибудь кратко объяснить, что было происходит в char -> Int продвижение который произвел 0xffffffef вместо 0x000000ef? "

Вопреки четырем ответам, пока нет.

Скорее, у вас было отрицательное значение char, которое в качестве условия switch было переведено в то же отрицательное значение int, как требуется для

C ++ 98 §6.4.2 / 2
Интегральные акции выполняются.

Затем с вашим 32-битным компилятором C ++ 0xffffffef был интерпретирован как литерал unsigned int, потому что он слишком велик для 32-битного int,

C ++ 98 2.13.1 / 2
Если он восьмеричный или шестнадцатеричный и не имеет суффикса, он имеет первый из этих типов в которые можно изобразить: int, unsigned int, long int, unsigned long int.

Теперь для метки case,

C ++ 98 §6.4.2 / 2
Интегральное выражение-константа (5.19) неявно преобразуется в тип условия переключения.

В вашем случае, со знаком типа назначения, результат преобразования формально определяется реализацией,

C ++ 98 §4.7 / 3
Если тип назначения подписан, значение не изменяется, если оно может быть представлено в типе назначения (и ширине битового поля); в противном случае значение реализации.

Но на практике почти все компиляторы используют двоичное представление дополнения без перехвата, и поэтому преобразование, определяемое реализацией, в вашем случае означает, что битовый шаблон 0xffffffef интерпретируется как спецификация дополнения двух отрицательного значения. Какое значение вы можете вычислить по 0xffffffef - 2 32 , потому что здесь мы говорим о 32-битном представлении. Или, так как это всего лишь 8-битное значение, которое было расширенным знаком до 32 бит, вы можете альтернативно рассчитать его как 0xef - 2 8 , где 0xef - код символа точка.

Приветствия и hth.,

1 голос
/ 07 июня 2011
...