Почему переполнение данных в типе данных char приводит к переносу значения в его диапазон? - PullRequest
0 голосов
/ 12 июля 2020

Недавно я наткнулся на этот вопрос и ответ, данный @ chux - Reinstate Monica .

Цитируя строки из его ответа: "Это поведение, определяемое реализацией. Присвоенное значение могло быть 0, 1 или 2 ... Обычно значение оборачивается ("модифицируется") путем добавления / вычитания 256, пока не попадет в диапазон. 100 + 100 -256 --> -56. "

Код:

#include <stdio.h>
int main(void)
{
 char a = 127;
 a++;
 printf("%d", a);
 return 0;
}

Вывод: -128

В большинстве компиляторов C тип char принимает 1 Byte размер и, строго говоря, я предполагаю его 16-битную систему, а char занимает 1 Byte.

Когда a = 127, его двоичное представление внутри компьютера - 0111 1111, увеличение его на 1 должно дать значение

0111 1111 + 0000 0001 = 1000 0000

, которое равно -0 (с учетом представления числа со знаком, где крайний левый бит представляет 0 = + and 1 = -), тогда почему результат равен -128?

Это из-за "ПРАВИЛА ПРОДВИЖЕНИЯ ЦЕЛОГО" ? Я имею в виду, что для этого выражения a + 1, a преобразуется в int (2 Bytes) перед операцией +, а затем его двоичное представление в памяти становится 1111 1111 1000 0000, что равно -128 и имеет смысл для вывода -128. Но тогда это мое предположение противоречит цитируемым строкам Chux-Reinstate-Monica об упаковке значений.

1 Ответ

1 голос
/ 12 июля 2020

1000 0000, что равно -0 ...

Единичное дополнение имеет -0, но большинство компьютеров используют два дополнения , чего нет.

В обозначении два дополнения крайний левый бит представляет -(coefficient_bit * 2^N-1), т.е. в вашем случае 1000 0000 крайний левый бит представляет -(1 * 2^8-1), что является равно -128, и поэтому результат такой же.

Ваш char - это 8-битное целое число со знаком, и в этом случае 1000 0000 равно -128. Мы можем проверить, что такое 1000 0000, удобно с помощью расширения GNU, которое допускает двоичные константы .

char a = 0b10000000;
printf("%d\n", a);    // -128

char в этой реализации является 8-битным целым числом со знаком. Добавление 1 к 127 приводит к переполнению целого числа до -128.

А как насчет целочисленного продвижения? Целочисленное продвижение происходит во время вычисления, но результат по-прежнему char. 128 не может поместиться в наш подписанный 8-битный char, поэтому он переполняется до -128.

Целочисленное продвижение демонстрируется в этом примере .

char a = 30, b = 40;
char c = (a * b);
printf("%d\n", c);      // -80

char d = (a * b) / 10;
printf("%d\n", d);      // 120

char c = (a * b); равно -80, а char d = (a * b) / 10; 120. Почему? Разве не должно быть -8? Ответ здесь - это целочисленное продвижение. Вычисления выполняются как собственные целые числа, но результат все равно должен быть помещен в 8-битный символ. (30 * 40) - 1200, что составляет 0100 1011 0000. Затем его нужно вставить обратно в 8-битовое целое число со знаком; это 1011 0000 или -80.

Для других расчетов (30 * 40) / 10 == 1200 / 10 == 120, что идеально подходит.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...