Как int преобразуется в char и как char преобразуется в int?
Автор вопроса: Igor LiferenkoОтветов: 3
В следующем примере выводится битовое представление byte со всеми единицами:
#include <stdio.h>
int main (void)
{
char c = 255;
char z;
for (int i = 7; i >= 0; i--) {
z = 1 << i;
if ((z & c) == z) printf("1"); else printf("0");
}
printf("\n");
return 0;
}
Выход 11111111
Теперь мы меняем char c на int c, чтобы пример стал таким:
#include <stdio.h>
int main (void)
{
int c = 255;
char z;
for (int i = 7; i >= 0; i--) {
z = 1 << i;
if ((z & c) == z) printf("1"); else printf("0");
}
printf("\n");
return 0;
}
Вывод 377, что означает, что glibc противоречит gcc, потому что подписанный символ автоматически преобразуется в беззнаковый. Почему такие сложности? Разумно иметь char без знака по умолчанию. Есть какая-то конкретная причина, почему нет?
Если вам нужна определенная разрядность, используйте типы фиксированной разрядности из stdint.h. И при смещении, как правило, лучше использовать беззнаковые типы, потому что определенные сдвиги/значения для целых чисел со знаком определяются реализацией или даже вызывают неопределенное поведение. too honest for this site 08.11.2016
Первая проблема здесь - тип char. Этот тип никогда не следует использовать для хранения целочисленных значений, поскольку он имеет определяемую реализацией подпись. Это означает, что он может быть как подписанным, так и неподписанным, и вы получите разные результаты на разных компиляторах. Если char не имеет знака в данном компиляторе, то этот код будет вести себя так, как вы ожидали.
Но если char подписано, char c = 255; приведет к слишком большому значению. Затем значение 255 будет преобразовано в число со знаком некоторым специфичным для компилятора способом. Обычно путем перевода значения необработанных данных в эквивалент дополнения до двух.
Хорошие компиляторы, такие как GCC, предупредят об этом: "переполнение при неявном преобразовании констант".
Устраните эту ошибку, никогда не используя char для хранения целых чисел. Вместо этого используйте uint8_t.
Та же проблема возникает, когда вы пытаетесь сохранить 1 << 7 внутри типа char, подписанного вашим компилятором. Когда это произойдет, z станет отрицательным значением (-128).
В выражении z & c оба операнда являются целочисленными, преобразованными в тип int. Это происходит в большинстве выражений C всякий раз, когда вы используете небольшие целочисленные типы, такие как char.
Оператор & не заботится о том, подписаны ли операнды или нет, он будет выполнять побитовое И над значениями "необработанных данных" переменных. Когда c является знаком char и имеет необработанное значение 0xFF, вы получите отрицательный результат с установленным битом знака. Значение -1 на компьютерах с дополнением до двух.
Итак, чтобы ответить, почему вы получаете разные результаты в двух случаях:
Когда вы переключаете тип на int, значение 255 помещается внутри c без преобразования в отрицательное значение. Результатом операции & также будет int, и бит знака этого int никогда не будет установлен, в отличие от случая char.
При выполнении -128 & 255 результатом будет 128 (0x80). Это положительное целое число. Однако z является отрицательным целым числом со значением -128. Он будет повышен до int оператором ==, но знак будет сохранен. Поскольку 128 не равно -128, старший бит будет напечатан как ноль.
Вы получите тот же результат, если переключите char на uint8_t.
Ответ 2 · Sumit Gemini
для char в int вы должны определить char как unsigned, потому что по умолчанию char или любой другой тип рассматривается как singed.
int main (void)
{
int c = 255;
unsigned char z;
int i;
for (i = 7; i >= 0; i--) {
z = 1 << i;
if ((z & c) == z) printf("1"); else printf("0");
}
printf("\n");
return 0;
}
Ответ 3 · Breaking not so bad
(изменить, чтобы уточнить "подписано по умолчанию")
В первом листинге (z == c) проверяет два char ; однако во втором листинге (z == c) проверяет один char и один int.
Для выполнения операций & и == между char и int компилятор расширяет char до размера int. эм>.
Что касается бита 7 (8-й):
Если ваш компилятор считает char беззнаковым по умолчанию, условие
(((int)(128) & (int)255) == (int)128)
будет отображаться true, и будет напечатано 1. Однако в вашем случае результат ложный, и отображается 0.
Причина, скорее всего, в том, что ваш компилятор считает char подписанным (например, gcc по умолчанию). В этом случае char, установленный в 1 << 7, на самом деле -128, а в int (не менее двух байтов) 255 является положительным.
(char)-128, расширенное до int, равно (int)-128, поэтому условие