Функция типа int не использует возвращаемый переполнение стека

Если у меня есть такая функция:

int addNumbers(int x, int y)
{
return x + y;
}

и если я использую его как таковой:

cout << addNumbers(4, 5) << endl;

Он вернется и распечатает 9, Используя то же самое cout строка выше, если я закомментирую или удаляю возврат в addNumbers, он вернется и распечатает 1, Если я сделаю это:

int addNumbers(int x, int y)
{
int answer = x + y;
//return x + y;
}

Он автоматически вернется и распечатает 9без меня с помощью возврата. Точно так же я могу написать int answer = x; и он вернется 4, Я также могу написать это:

int addNumbers(int x, int y)
{
int answer = x;
answer = 1;
//return x + y;
}

и он все равно вернется 4.

Что именно возвращается и почему? Он только возвращает что-то отличное от 1, когда я использую переменные параметра, но не возвращает ответ переменной, как показано в последнем примере, потому что я изменил его на 1, и он все еще вернул значение x (4),

2

Решение

§6.6.3 [stmt.return] / p2:

Вытекающий из конца функции эквивалентен return без
значение; это приводит к неопределенному поведению в возвращающем значение
функция.

(main() это особое исключение. Стекает с конца main() эквивалентно return 0;)

Допустимые УБ включают в себя:

  • Возвращать то, что вы «хотели» вернуть
  • Вместо этого возвращаем мусор
  • грохот
  • Отправка вашего пароля хакерам
  • Форматирование вашего жесткого диска
  • Заставить ваш компьютер взорваться и сбить ваши ноги
  • Заклинание носовых демонов
  • Путешествие во времени и исправление вашей программы
  • Создание черной дыры
  • ……

А если серьезно, UB может проявляться во всех видах способов. Например, учитывая этот код:

#include <iostream>
bool foo = false;
int addNumbers(int x, int y)
{
int answer = x;
answer = 1;
//return x + y;
}

int main(){
if(!foo) {
addNumbers(10, 20);
std::cout << 1 << std::endl;
}
else {
std::cout << 2 << std::endl;
}
}

лязг ++ в -O2 печать 2,

Зачем? Потому что это выводило, что addNumbers(10, 20); имеет неопределенное поведение, что позволяет предположить, что первая ветвь никогда не берется и что foo всегда trueдаже если это явно не так.

3

Другие решения

Вы полагаетесь на «неопределенное поведение». Возвращаемое значение для простых типов обычно хранится в регистре, который также может использоваться при формировании результата вычисления. Но он также НЕ может быть использован, и вы получите произвольный «случайный» результат, и, будучи «неопределенным поведением», вы также можете получить любую другую возможную операцию, которую может выполнить ваш компьютер — например, сбой или выполнение некоторого кода, который вы не сделали хочу выполнить …

1

Вы наблюдаете неопределенное поведение. Нет веской причины «почему» программа делает это, потому что это не правильно сформированная программа. Он может сделать что угодно, в том числе удалить себя с диска при запуске. Включить предупреждения и ошибки компилятора (например, g++ -Wall -Wextra -Werror) и вам будет автоматически запрещено писать такой код (как и должно быть).

0

Таким образом, это неопределенное поведение, разборка вашего двоичного файла может объяснить, почему возвращаются такие значения.

objdump -d example.bin

Поскольку возвращаемое значение связано с реестром rax, если компилятор использует rax для обработки функции, возвращаемое значение является значением, которое остается в rax.

В любом случае, вы не должны этого делать, потому что когда вы пишете такой код, оптимизации компилятора и использование реестров неизвестны.

0
По вопросам рекламы [email protected]