Модуль, использующий странное поведение размера строки - PullRequest
1 голос
/ 15 апреля 2020

Пожалуйста, объясните, почему первый фрагмент кода не приводит к значению -1.

    string s = "abc";
    int amount = -1;
    cout << "amount to shift before modulus: " << amount<<endl;
    amount %= s.size();
    cout << "mod " <<s.size()<<endl;
    cout << "amount to shift after modulus: " << amount<<endl;

Вывод:
величина сдвига до модуля: -1
mod 3
сумма для сдвига после модуля: 0

    string s = "abc";
    int sSize = s.size();
    int amount = -1;
    cout << "amount to shift before modulus: " << amount<<endl;
    amount %= sSize;
    cout << "mod " <<sSize<<endl;
    cout << "amount to shift after modulus: " << amount<<endl;

Вывод:
сумма для сдвига до модуля: -1
мод 3
сумма для сдвига после модуля: -1

Я выполнил задание по кодированию, когда столкнулся с этим поведением, и я не понимаю, что происходит. Такое поведение не происходит, если сумма является положительным числом, например 1.

1 Ответ

4 голосов
/ 15 апреля 2020

Если вы выполняете арифметику 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 ++ выводит отрицательные числа при использовании по модулю? для получения дополнительной информации.)

...