Почему 00000000 - 00000001 = 11111111 в типе данных C unsigned char?

Я заметил, что, когда переменная типа unsigned char хранит значение 0 (00000000 2) и уменьшается на 1 (00000001 2), значение переменной превращается в 255 (11111111 2), что является наивысшим значением, которое может содержать переменная типа unsigned char.

У меня вопрос: почему 00000000 2 - 00000001 2 превращается в 11111111 2? (Я хочу увидеть стоящую за этим арифметику)

Код C, в котором я это наблюдал, был следующим:

#include <stdio.h>

main(){

  unsigned char c = 0;

  unsigned char d = c - 1;

  printf("%d\n%d", c, d);

}

Когда он запускается, отображается следующий вывод:

0
255

person samuel    schedule 05.02.2020    source источник
comment
Это называется модульной арифметикой, и это вполне разумный подход к работе с числами без знака. И по той же причине, по которой ответ на вычитание 1 часа из 00:00 даст вам 23:00 вместо -01: 00.   -  person Groo    schedule 05.02.2020
comment
Вы знаете, как, когда шестизначный автомобильный одометр продолжается от 999999 до 000000? Если бы он двигался назад от 000000, он перешел бы на 999999. Переход от 00000000 к 11111111 в двоичном формате - это то же самое.   -  person Eric Postpischil    schedule 05.02.2020
comment
Подробно обработайте цифры справа налево: сначала у нас есть 0 минус 1: 1 больше, поэтому мы «заимствуем» 1 из цифры слева. Тогда у нас есть 10 минус 1, что дает 1. В следующей позиции у нас 0 минус 0 минус заимствование 1, так что это 0 минус 1. Мы снова занимаем и получаем 1 в результате. Это продолжается до последней позиции, где мы снова занимаем 1 и в результате получаем 1. Теперь у нас есть восемь единиц в качестве результирующих битов и заимствование из позиции слева, которая находится за пределами восьми битов и отбрасывается или игнорируется.   -  person Eric Postpischil    schedule 05.02.2020
comment
что вы ожидали?   -  person 0___________    schedule 05.02.2020
comment
@EricPostpischil, но как мы можем позаимствовать 1 у 0?   -  person samuel    schedule 05.02.2020
comment
@samuel, вы должны принять это как аксиому. .   -  person 0___________    schedule 05.02.2020
comment
@samuel: Ну, 0 недостаточно для заимствования, поэтому вы одалживаете 1 слева. Получается 10, и из этого можно вычесть 1. Пока я пишу, это работает до последней цифры, после чего мы заимствовали 100000000 (256 в десятичной системе). То есть вместо 0000 0000 - 0000 0001 у нас есть 1 0000 0000 - 0000 0001, что явно 1111 1111. Это работает только в том случае, если вам разрешено одолжить 1 0000 0000, которого у вас нет. Это то же самое, что и работа по модулю 256.   -  person Eric Postpischil    schedule 05.02.2020


Ответы (1)


См. здесь:

Арифметика беззнаковых целых чисел всегда выполняется по модулю 2 n, где n - количество битов в этом конкретном числе. Например. для unsigned int добавление единицы к UINT_MAX дает ​0, а вычитание единицы из ​0 дает UINT_MAX.

Итак, в вашем примере, поскольку unsigned char обычно 8-битный, вы получаете 2 8 -1 = 255.

person Blaze    schedule 05.02.2020