В общем, обратитесь к 5/9 в стандарте.
В вашем примере значение со знаком преобразуется в без знака (принимая его мод UINT_MAX +1), затем выполняется вычитание по модулю UINT_MAX + 1 для получения результата без знака.
Сохранение этого результата в виде значения со знаком в s
включает стандартное интегральное преобразование - это в 4.7 / 3.Если значение находится в диапазоне signed int
, то оно сохраняется, в противном случае это значение определяется реализацией.Все реализации, на которые я когда-либо смотрел, использовали арифметику по модулю, чтобы задвинуть ее в диапазон от INT_MIN
до INT_MAX
, хотя, как говорит Крит, вы можете получить предупреждение за это неявное выполнение.
"Трюк"Реализации, с которыми вы, вероятно, никогда не будете иметь дело, могут иметь разные правила для unsigned-> подписанного преобразования.Например, если реализация имеет представление знаковых целых чисел со знаком, то всегда невозможно выполнить преобразование, взяв модуль, поскольку нет способа представить +/- (UNIT_MAX+1)/2
в виде целого числа.
Также имеет значение 5.17 / 7, «Поведение выражения вида E1 op= E2
эквивалентно E1 = E1 op E2
, за исключением того, что E1
вычисляется только один раз».Это означает, что для того, чтобы сказать, что вычитание выполняется в типе unsigned int
, все, что нам нужно знать, это то, что s - u
выполняется в unsigned int
: для -=
нет специального правила, что арифметика должна выполняться вТип LHS.