2147483648
не является 32-битным int
, оно чуть выше INT_MAX
, значение которого на таких платформах равно 2147483647
.
int b = 2147483648;
определяется реализацией.На вашей платформе он, похоже, выполняет 32-разрядное преобразование, что типично для двух дополнительных архитектур, но не гарантируется стандартом C.
Как следствие printf("%d\n", b);
вывод -2147483648
.
Остальная часть кода отлично определена в 32-разрядных системах, и вывод 2147483649
является правильным и ожидаемым.Тот факт, что ОС на 64 бит играет очень тонкую роль на этапах оценки, но в основном не имеет отношения к фактическому результату, который полностью определяется стандартом C.
Вот шаги:
unsigned int a = 2147483650;
здесь нет ничего удивительного, a
- это unsigned int
, а его инициализатор - int
, long int
или long long int
, в зависимости от того, какойиз этих типов имеет не менее 32 битов значения.В Windows и 32-битной Linux это будет long long int
, тогда как в 64-битной Linux это будет long int
.Значение сохраняется до 32-битного при сохранении в переменную unsigned int
.
Вы можете проверить эти шаги, добавив следующий код:
printf("sizeof(2147483650) -> %d\n", (int)sizeof(2147483650));
printf(" sizeof(a) -> %d\n", (int)sizeof(a));
ВторойОпределение unsigned int c = a+(-1);
подвергается тем же шагам:
c
определяется как unsigned int
, и его инициализатор усекается до 32 бит при сохранении в c
.Инициализатор является дополнением: - первый член -
unsigned int
со значением 2147483650U
. - второй член - это выражение в скобках с унарным отрицанием
int
со значением1
.Следовательно, это int
со значением -1
, как вы правильно проанализировали. - второй член преобразуется в
unsigned int
: преобразование выполняется по модулю 2 32 , следовательно, значение4294967295U
. - затем выполняется сложение с использованием арифметики без знака, которая определяется как выполняемая по модулю ширины типа
unsigned int
, следовательно, результатом является unsigned int
со значением 2147483649U
, (6442450945
по модулю 2 32 ) - Это значение
unsigned int
сохраняется в c
и печатается правильно с printf("%u\n", c);
как 2147483649
.
Если бы выражение было вместо 2147483650 + (-1)
, вычисление было бы выполнено в 64-битной арифметике со знаком, с типом long int
или long long int
в зависимости от архитектуры, с результатом 2147483649
,Это значение затем будет усечено до 32 бит при сохранении в c
, следовательно, то же значение для c
, что и 2147483649
.
Обратите внимание, что описанные выше шаги не зависят от фактического представления отрицательного значения.ценности.Они полностью определены для всех архитектур, имеет значение только ширина типа int
.
Вы можете проверить эти шаги с помощью дополнительного кода.Вот полная инструментальная программа, иллюстрирующая эти шаги:
#include <limits.h>
#include <stdio.h>
int main(void) {
printf("\n");
printf(" sizeof(int) -> %d\n", (int)sizeof(int));
printf(" sizeof(unsigned int) -> %d\n", (int)sizeof(unsigned int));
printf(" sizeof(long int) -> %d\n", (int)sizeof(long int));
printf(" sizeof(long long int) -> %d\n", (int)sizeof(long long int));
printf("\n");
int b = 2147483647; // To show the maximum value of int type here is 2147483647
printf(" int b = 2147483647;\n");
printf(" b -> %d\n",b);
printf(" sizeof(b) -> %d\n", (int)sizeof(b));
printf(" sizeof(2147483647) -> %d\n", (int)sizeof(2147483647));
printf(" sizeof(2147483648) -> %d\n", (int)sizeof(2147483648));
printf(" sizeof(2147483648U) -> %d\n", (int)sizeof(2147483648U));
printf("\n");
unsigned int a = 2147483650;
printf(" unsigned int a = 2147483650;\n");
printf(" a -> %u\n", a);
printf(" sizeof(2147483650U) -> %d\n", (int)sizeof(2147483650U));
printf(" sizeof(2147483650) -> %d\n", (int)sizeof(2147483650));
printf("\n");
unsigned int c = a+(-1);
printf(" unsigned int c = a+(-1);\n");
printf(" c -> %u\n", c);
printf(" sizeof(c) -> %d\n", (int)sizeof(c));
printf(" a+(-1) -> %u\n", a+(-1));
printf(" sizeof(a+(-1)) -> %d\n", (int)sizeof(a+(-1)));
#if LONG_MAX == 2147483647
printf(" 2147483650+(-1) -> %lld\n", 2147483650+(-1));
#else
printf(" 2147483650+(-1) -> %ld\n", 2147483650+(-1));
#endif
printf(" sizeof(2147483650+(-1)) -> %d\n", (int)sizeof(2147483650+(-1)));
printf(" 2147483650U+(-1) -> %u\n", 2147483650U+(-1));
printf("sizeof(2147483650U+(-1)) -> %d\n", (int)sizeof(2147483650U+(-1)));
printf("\n");
return 0;
}
Вывод:
sizeof(int) -> 4
sizeof(unsigned int) -> 4
sizeof(long int) -> 8
sizeof(long long int) -> 8
int b = 2147483647;
b -> 2147483647
sizeof(b) -> 4
sizeof(2147483647) -> 4
sizeof(2147483648) -> 8
sizeof(2147483648U) -> 4
unsigned int a = 2147483650;
a -> 2147483650
sizeof(2147483650U) -> 4
sizeof(2147483650) -> 8
unsigned int c = a+(-1);
c -> 2147483649
sizeof(c) -> 4
a+(-1) -> 2147483649
sizeof(a+(-1)) -> 4
2147483650+(-1) -> 2147483649
sizeof(2147483650+(-1)) -> 8
2147483650U+(-1) -> 2147483649
sizeof(2147483650U+(-1)) -> 4