В C оценка выражения определяется оператором и его операндами, а не местом, где результат будет в конечном итоге сохранен.
Выражение a * b * d
структурировано как (a * b) * d
.Таким образом, a * b
оценивается, а затем результат умножается на d
.
Одно из правил для *
содержится в C 2018 6.5.5 3:
Обычные арифметические преобразования выполняются над операндами.
Обычные арифметические преобразования определены в 6.3.1.8 1. Они немного сложны, и я привожу большинство деталейниже.Применяя их к вашему примеру:
- В
a * b
, a
- это uint32_t
, а b
- uint8_t
. - Целое число преобразования
b
в int
- по существу, вся арифметика в C
выполняется с шириной не менее int
. - Если
int
равен 32 битам или уже, a
остается uint32_t
.В противном случае a
преобразуется в int
. - Если преобразованные типы
a
и b
оба равны int
, преобразования выполняются и выполняется умножение. - Если преобразованный тип
a
равен uint32_t
, b
преобразуется в uint32_t
и выполняется умножение. - Затем умножение на
d
выполняется аналогичным образом.
Итак, если int
равен 32 битам или уже, умножения выполняются с uint32_t
, а результат равен uint32_t
.Если int
шире, умножения выполняются с int
, и в результате получается int
.
Приведение любого операнда к uint64_t
приведет к выполнению арифметики с uint64_t
.(За исключением того, что теоретически возможно, что int
шире, чем uint64_t
, в этом случае арифметика будет выполнена с int
, но это все же удовлетворительно - выполнение приведения гарантирует, что арифметика будет выполнена по крайней мере с этой шириной.)
Для действительных чисел обычные арифметические преобразования в основном следующие:
- Если один из операндов равен
long double
, другой преобразуется в long double
. - В противном случае, если любой из них равен
double
, другой преобразуется в double
. - В противном случае, если один из них равен
float
, другой преобразуется в float
. - В противном случае, целочисленные преобразования выполняются для обоих операндов.
- Затем, если оба имеют одинаковый тип, дальнейшее преобразование не выполняется.
- В противном случае, если оба подписаны илиоба без знака, более узкий (на самом деле «меньший ранг») операнд преобразуется в тип другого.
- В противном случае, если беззнаковый операнд имеет одинаковую ширину или шире (больший или равный ранг), подписанный операндоперандпреобразуется в тип операнда без знака.
- В противном случае, если тип операнда со знаком может представлять все значения типа операнда без знака, операнд без знака преобразуется в тип операнда со знаком.
- В противном случае оба операнда преобразуются в тип без знака, ширина которого равна ширине операнда со знаком.
Целочисленные продвижения определены в 6.3.1.1 2. Они применяются квсе целочисленные типы шириной или int
или unsigned int
(технически с рангом, меньшим или равным рангу int
и unsigned int
), включая битовые поля типа _Bool
, int
, signed int
или unsigned int
.
Если int
может представлять все значения исходного типа (как ограничено шириной для битового поля), значение преобразуетсяна int
;в противном случае он конвертируется в unsigned int
.Они называются целочисленными акциями.Все остальные типы не изменяются целочисленными акциями.