Функция возвращает значение без оператора возврата

Почему следующий код имеет правильный вывод? int GGT не имеет оператора возврата, но код все равно работает? Глобальных переменных не задано.

#include <stdio.h>
#include <stdlib.h>

int GGT(int, int);

void main() {
    int x1, x2;
    printf("Bitte geben Sie zwei Zahlen ein: \n");
    scanf("%d", &x1);
    scanf("%d", &x2);
    printf("GGT ist: %d\n", GGT(x1, x2));
    system("Pause");
}

int GGT(int x1, int x2) {
    while(x1 != x2) {
        if(x1 > x2) {
            /*return*/ x1 = x1 - x2;
        }
        else {
            /*return*/ x2 = x2 - x1;
        }
    }
}

Ответ 1

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

Поскольку eax используется как регистр возврата, он часто используется как регистр "царапины" calee, потому что его не нужно сохранять. Это означает, что очень возможно, что он будет использоваться как любая из локальных переменных. Поскольку оба они равны в конце, более вероятно, что правильное значение останется в eax.

Ответ 2

Он не должен работать и, конечно же, не работает на всех компиляторах и целевой ОС, даже если он работает на вашем.

Вероятное объяснение состоит в том, что возвращаемая функция int всегда возвращает что-то, и обычно это содержимое регистра. Вероятно, регистр, используемый для возвращаемого значения, в вашем случае тот же, что и для вычисления последнего выражения, перед возвратом из функции (по объектам x86, конечно же, eax).

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

Я тестировал его с помощью gcc:

gcc без оптимизации: входы 10, 20 → результат 10

gcc -O1 входы 10, 20 → результат 1

gcc-O2 входы 10, 20 → результат 0

Ответ 3

В x86 возвращаемое значение сохраняется в регистре EAX, который "случайно" также используется этим компилятором для хранения результата арифметических операций (или, по крайней мере, вычитания). Вы можете проверить это, посмотрев сборку, сгенерированную вашим компилятором. Я согласен с kriss - вы не можете предположить, что это всегда будет так, поэтому лучше явно указать возвращаемое значение.

Ответ 4

GCC вставляет инструкцию "ret" в этом случае, в то время как clang pastes "ud2" и приложение вылетают во время выполнения.

Ответ 5

Вам не нужен оператор возврата, если вы используете указатели. Как правило, вы можете вернуть только одно значение по оператору Return, но если вы используете указатели, вы можете вернуть сколько хотите.

scanf ( "% d", & x1); там вы даете функцию Adress of X1, а не значение X1. указатели работают с шириной адресов. вы можете читать книги, чтобы узнать, как работать с указателями.