Код в цикле for
в processChange
делает это:
- Если
remainder
равно нулю, выполнить расчет и вернуть.
- Если
centsChange
равно единице, вернуть.
- Если
centsChange
равен хотя бы arr[i]
, выполните расчет и вернитесь.
- В противном случае, достигните конца цикла
for
и продолжите итерацию.
Насколько может сказать компилятор, значение i
достигнет четырех, и управление выйдет из цикла for
. В этот момент управление переходит к концу функции, где нет оператора return
. Таким образом, компилятор предупреждает вас, что элемент управления достигнет конца не пустой функции. («Не пустая функция» - это функция с типом возврата, который не является void
. Тип возврата processChange
равен int
.)
Один из способов исправить это - вставить оператор return
в конец функции.
Другой способ - отключить предупреждения компилятора для этой ситуации, что можно сделать с GCC и Clang с помощью ключа командной строки -Wno-return-type
.
Мы можем видеть, что элемент управления не может фактически оставить оператор for
, потому что, когда i
равен трем, arr[i]
равен единице, поэтому centsChange % arr[i]
обязательно выдает ноль, который присваивается remainder
, вызывая код для впадают в первый случай выше. С помощью GCC и Clang вы можете сообщить об этом компилятору, вставив __builtin_unreachable();
как последний оператор в функцию. Это говорит компилятору, что эта точка в коде логически не может быть достигнута любой комбинацией обстоятельств в программе. (Использование этой функции компилятора, если неверно, что элемент управления не может достичь местоположения, приведет к прерыванию вашей программы.)
Обратите внимание, что тот факт, что элемент управления не может выйти из цикла for
по вышеуказанной причине, означает, что базовый случай centsChange == 1
не требуется. Тот факт, что remainder == 0
должен быть удовлетворенным в какой-то момент, означает, что он служит базовым случаем.
Хотя этот анализ обсуждает код как есть, опытные программисты реструктурируют код так, что ни одно из вышеперечисленных решений не требуется. Бывают случаи, когда различные сложности побуждают нас использовать код, когда компилятор не может сделать вывод, что определенная точка никогда не достигается при исполнении, но мы знаем, что это так, и вышеупомянутые обходные пути могут использоваться в таких случаях. Однако это не один из них. Этот код довольно прост и может быть реструктурирован, чтобы поток управления был проще и понятнее для компилятора.