Если вы выполняете арифметику c (включая сравнение арифметики c) между целым числом со знаком и целым числом без знака, а тип целого числа без знака по крайней мере такой же ширины, как целое число со знаком, тогда целое число со знаком преобразуется в целое число без знака . (Это результат так называемых "обычных арифметических c преобразований" .)
Это почти всегда дает неожиданные результаты, если только арифметическая c операция не является сложением или вычитанием , Во многих случаях хороший компилятор предупредит вас о выполнении арифметики со смешанным знаком c, если вы запросите предупреждения. (Настоятельно рекомендуется!) Это всего лишь один относительно необычный вариант.
В первом случае s.size()
имеет тип size_t
, который является беззнаковым типом, вероятно, из 64 битов; следовательно, он шире int
. Таким образом, чтобы вычислить amount % s.size()
, компилятор сначала преобразует amount
в беззнаковое size_t
, что приведет к 2 64 -1. Так получилось, что это число делится на 3, поэтому операция по модулю возвращает 0.
Во втором случае вы принудительно преобразуете s.size()
в целое число со знаком. Поскольку значение определенно находится в пределах int
, конверсия четко определена. Последующая операция по модулю выполняется для int
s, которые подписаны, и дает ожидаемый результат, если вы ожидаете, что со знаком по модулю будет работать так же, как в C ++. (См. Почему C ++ выводит отрицательные числа при использовании по модулю? для получения дополнительной информации.)