Переполнение, когда uint64 = uint8 * uint8

#c

#c

Вопрос:

Я пробую приведенный ниже код:

 UINT a = 32768;
UINT b = 32768;
UINT64 c = a * b * 4;  // c = 0,  overflow...;
UINT64 d = (UINT64)a * (UINT64)b * 4;  // d = 4294967296, the right answer;
 

почему UINT64 c = a * b * 4 будет переполнением?

Я думаю, что a * b * 4 сначала сохранит значение temp UINT, а затем присвоит параметру c ? Правильно ли это?

Я хочу поискать в Google какую-нибудь подсказку, но я не знаю, какое ключевое слово мне следует использовать.

Спасибо

Комментарии:

1. Арифметические операторы

2. Ваше предположение верно. Вся операция не является атомарной.

3. Это помогло бы, если бы вы использовали стандартные типы. Что такое UINT?

4. И uint8 ? И как это UINT соотносится с uint8 и 32768 ?

Ответ №1:

 UINT a = 32768;
UINT b = 32768;
UINT64 c = a * b * 4;
 

вычисляется как

 UINT a = (UINT) 32768;
UINT b = (UINT) 32768;
UINT64 c = (UINT) a * (UINT) b * (int) 4;
 

Когда UINT недостаточно места для хранения UINT*UINT , вы получаете переполнение.

Вы можете исправить это, приведя один из UINT s к UINT64 подобному:

 UINT64 c = (UINT64) a * b * 4;
 

Ответ №2:

По той же причине, по которой

 double x=1/2;
 

будет равно 0, но

 double y=double(1)/2;
 

будет 0.5 .

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

В вашем случае все вычисляется с точностью до 32 бит, переполнение происходит до преобразования в 64 бита.

Ответ №3:

В uint64 c его правая часть автоматически присваивается как uint, потому что A и B оба являются uint, после чего он присваивает ответ c (уже переполненный). Чтобы убедиться, что этого не произойдет, ОДНА из переменных в c также должна быть uint64, и тогда она не будет переполняться. Вот почему int64 d работает, потому что он также был назначен.

Ответ №4:

Ваше предположение верно. Поскольку a и b являются значениями UINT, операция выполняется как UINT, и во время a * b * 4, что равно 2 ^ 32, она переполняется в 32-битном UINT как 0. Результат только затем преобразуется в UINT64.