Двусмысленность в арифметике длинного целого?

Взгляните на следующую часть кода:

#include 

int main(void)  
{  
int a;

a = 2147483647;
printf("a + 1 = %d \t sizeof (a + 1) = %lu\n", a + 1, sizeof (a + 1));
printf("a + 1L = %ld \t sizeof (a + 1L) = %lu\n", a + 1L, sizeof (a + 1L));

a = -1;
printf("a + 1 = %d \t sizeof (a + 1) = %lu\n", a + 1, sizeof (a + 1));
printf("a + 1L = %ld \t sizeof (a + 1) = %lu\n", a + 1L, sizeof (a + 1L));  //why a + 1L does not yield long integer ?

return 0;
}  

Это приводит к следующей продукции:

a + 1 = -2147483648   sizeof (a + 1) = 4  
a + 1L = 2147483648   sizeof (a + 1L) = 8  
a + 1 = 0    sizeof (a + 1) = 4  
a + 1L = 0   sizeof (a + 1) = 8

Почему действительно + 1L в последней линии уступают 0 вместо длинного целого как 4294967296?

1
nl ja de

2 ответы

почему + 1L в последней линии не приводит к длинному целому как 4294967296?

Поскольку, преобразовывая интервал -1 к длинное целое приводит к длинное целое со стоимостью-1 и -1 + 1 = 0 .

Преобразование -1 к другому типу только привело бы к 4294967295 , если целевой тип - неподписанный 32-битный тип (обычно, , неподписанный интервал является таким, обычно, uint32_t , если обеспечено). Но тогда, добавление 1 к стоимости обернуло бы к 0.

Таким образом, чтобы получить 4294967296 , вам был бы нужен промежуточный бросок,

(uint32_t)a + 1L

так, чтобы -1 был сначала преобразован в uint32_t со стоимостью 4294967295 , и это тогда преобразовывается, чтобы долго .

5
добавлено
Нет, арифметические преобразования сохраняют стоимость, если она может быть представлена в целевом типе. Таким образом, если вы преобразовываете стоимость от типа целого числа со знаком до большего типа целого числа со знаком, вы получаете расширение знака (если представление - two' s дополнение, как почти универсально имеет место в наше время).
добавлено автор Daniel Fischer, источник
@rootkea Вы mustn' t использование %ld с , короткий аргумент, that' s неопределенное поведение. То, какой , вероятно произошел: s преобразовывается, чтобы интервал , передавая его, чтобы printf (продвижение параметра по умолчанию для функций variadic), давая 32 1 бит. С %ld формат, printf захватил 64 бита из регистра, это ожидает аргумент в [принятие обычного x86_64 поведения], и другие 32 бита были всем 0 (нормальный, когда вы загружаете 32 битовых значения в 64-битном регистре), таким образом, вы получили 2^32-1 напечатанный.
добавлено автор Daniel Fischer, источник
О! И я думал интервал -1 продвинут, чтобы длинное целое просто, приложив дополнительный 0' s, таким образом, добираясь длинное целое как 4294967295.
добавлено автор rootkea, источник
Спасибо за то разъяснение!:)
добавлено автор rootkea, источник
Эй @Daniel, взгляните на этот код: короткий s =-1; printf ("s = %hd\n", s); printf ("s = %d\n", s); printf ("s = %ld\n", s); Это дало мне продукцию как s =-1 s =-1 s = 4294967295 В последней линии, почему 4294967295 и не -1 как, продвигая C сохраняет ценность переменной?
добавлено автор rootkea, источник

В первом случае: 2147483647 подписанная стоимость 32 битов с шестнадцатеричным представлением 0x7fffffff. Добавление 1 к нему дает вам 32 битовых значения, шестнадцатеричный 0x80000000, который является-2147483648 в 32 битах, подписал интервал (должный переполниться) и ценность 2147483648, если рассмотрено, как 64 бита подписали интервал.

Во втором случае: - 1 подписанная стоимость 32 битов с шестнадцатеричным представлением 0xffffffff. Добавление 1 к нему дает вам 32 битовых значения, шестнадцатеричный 0x00000000, который является 0 в подписанном интервале.

Когда вы добавляете 1 к нему в 64 битах, расширение знака сначала происходит, таким образом, вы действительно добавляете 0xFFFFFFFFFFFFFFFF и 0x0000000000000001, сумма 0 как ожидалось.

Нет двусмысленности, если вы рассматриваете расширение знака.

1
добавлено