2014-09-06 9 views
2

Если у меня есть функция, как это:Функция типа междунар не используется возвратный C++

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).

+1

это UB, он возвращает это, потому что его то, что происходит в стеке, построено для x64, и это будет «случайное» значение. – paulm

+1

Это [* неопределенное поведение *] (http://en.wikipedia.org/вики/Undefined_behavior). –

ответ

2

§6.6.3 [stmt.return]/p2:

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

(main() является специальным исключением.Измельчитель с конца main() эквивалентно return 0;)

Допустимое UB включают:

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

Но серьезно, 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 prints2.

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

+0

Итак, хотя в этом (очень базовом) сценарии он всегда возвращает то, что я «ожидал», чтобы оно возвращалось, оно, конечно же, не гарантируется на других машинах или в более сложных сценариях? – Sam

+0

@Sam Не гарантируется ничего. * Все что угодно может случиться с UB. –

+0

Спасибо за ответ, и тот пример, который вы добавили, действительно помог. Странные вещи, действительно интересные тоже. – Sam

0

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

1

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

0

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

objdump -d example.bin

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^