Без знака int(32 бита) в unsigned long long (64 бита)

В приведенном ниже коде я умножил 0xffffffff на 2 для unsigned int(32 бита) и сохранил его в unsigned long long(64-битный). Почему я не получаю фактический результат, который 8589934588, Вместо этого я получаю 4294967294, Заранее спасибо. ВЫХОД: Размер i=4 Размер J=8 2xi=4294967292

/* Code starts here */
#include <stdio.h>
#include <stdlib.h>

int main (void) 
{
    unsigned int i=4294967294;
    unsigned long long j=i*2;
    printf("Sizeof i=%d\n", sizeof(i));
    printf("Sizeof J=%d\n", sizeof(j));
    printf("2xi=%llu\n", j);

    return 0;
}

3 ответа

Решение

Это потому что i*2 это умножение целого числа. Даже если вы храните его в long longВы все еще делаете целочисленную математику, которая вызывает переполнение.

Следующий код работает, так как мы продвигаем его до long long умножать

#include <stdio.h>
#include <stdlib.h>
int main (void)
{
  unsigned int i=4294967294;
  unsigned long long j=((unsigned long long)i)*2;
  printf("Sizeof i=%d\n", sizeof(i));
  printf("Sizeof J=%d\n", sizeof(j));
  printf("2xi=%llu\n", j);

  return 0;
}

Результат:

bash-4.1$ gcc long.c
bash-4.1$ ./a.out
Sizeof i=4
Sizeof J=8
2xi=8589934588

i*2 ничего не знает о том, что он назначается на unsigned long long - поскольку i является unsigned int а также 2 является int умножение выполняется с использованием unsigned int тип, который дает результат, который вы получили.

Вы можете решить проблему, сделав 2 unsigned long long буквальный, который способствует i в unsigned long long для умножения или приведения i в unsigned long long перед умножением, которое имеет тот же эффект:

unsigned long long j=i*2ULL;
/* or */
unsigned long long j=((unsigned long long)i)*2;

В общем, помните: в C цель присваивания / инициализации не влияет на то, как вычисляется выражение справа от него - используемые типы определяются только типами операндов.

Поскольку i является unsigned int а также 2 является int и будет повышен до unsigned int операция просто обернется. Одним из решений было бы бросить i в unsigned long long:

unsigned long long j = ((unsigned long long)i)*2 ;

Соответствующий раздел из проекта стандарта C11 находится в 6.2.5/9:

Вычисления с участием беззнаковых операндов никогда не могут переполниться, потому что результат, который не может быть представлен результирующим целочисленным типом без знака, уменьшается по модулю на число, которое на единицу больше наибольшего значения, которое может быть представлено результирующим типом.

Другие вопросы по тегам