Как проги C ++ получают свое возвращаемое значение, если в функции не указано возвращаемое значение? - PullRequest
5 голосов
/ 11 августа 2010

Я недавно написал сообщение:
Странная ошибка в программе на C ++: Удаление программы разрывов распечатки

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

Как выяснилось, моя проблема заключалась в том, что я забыл вернуть свой флаг успеха / ложного успеха, который позже использовал для логики.

Ноочевидно, ЧТО-то возвращалось, и что-то всегда было правдой, если бы я оставил этот кут, но, казалось бы, «волшебным образом» стало бы ложным, когда я его вынул.

Мой вопрос ко всем вам:
Что определяет, что функция c ++ возвращает, когда в функции не выполняется команда return?Есть ли в этом какая-то логика?

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

Удивительно, g ++ не дал мне никакогопредупреждения или ошибки при компиляции исполняемого файла, например:

g++ main.cc -g -o it_util

Моя версия: g ++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-44)

Опять же, чтобы спасти других от разочарования в будущем, если они совершат ту же глупую ошибку и столкнутся с тем же, казалось бы, ошибочным поведением, может ли кто-нибудь пролить свет на то, где функция без возврата получает свое возвращаемое значение из ??

Спасибо !!

Ответы [ 6 ]

5 голосов
/ 11 августа 2010

В соглашениях о вызовах x86 возвращаемое значение для целых чисел и указателей находится в регистре EAX.Ниже приведен пример этого:

int func() {
    if(0) return 5; // otherwise error C4716: 'func' : must return a value
}
int main() {
    int a;
    a = func();
}

Компиляция с cl.exe /Zi, MSVC ++ 10:

push    ebp
mov     ebp, esp
push    ecx
call    j_?func@@YAHXZ  ; func(void)
mov     [ebp+a], eax ; assumes eax contains the return value
xor     eax, eax
mov     esp, ebp
pop     ebp
retn

Конечно, это все неопределенное поведение.

5 голосов
/ 11 августа 2010

В этом нет логики, и большинство компиляторов C ++ должны пометить это предупреждением.Это допускало обратную совместимость с C.

В K & R C не было типа void, а когда тип не был указан, по умолчанию используется int.Итак,

myfunc() {....}

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

Компилятор должен был понять это.Итак, соглашение стало таким, что return поместит что-то в регистр.И присваивание в вызывающей подпрограмме вывело бы значение из регистра.Теперь, если вызываемый никогда не выдавал возврат, ничто специфичное не будет помещено в этот регистр.Но оно все равно будет иметь некоторое (случайное) значение, которое будет слепо назначено вызывающей стороне.

4 голосов
/ 11 августа 2010

из C ++ Стандартный раздел 6.6.3 Оператор возврата

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

Существует одно исключение (согласно 3.6.1 / 5):

Если управление доходит до конца основного, не встречая возврата утверждение, эффект от выполнение return 0;

Причина, по которой это синтаксически разрешено, хорошо описана Джеймсом Керраном . Но с опцией -Wall gcc (как прокомментировал Нил) вы должны быть предупреждены об этом поведении; что-то вроде «Не все пути управления возвращают значение в функции, возвращающей значение ...».

1 голос
/ 11 августа 2010

Это зависит от соглашения о вызовах. Например, для возврата 32-разрядного целого на платформе Intel вы получаете все, что находится в регистре eax.

0 голосов
/ 11 августа 2010

"Что определяет, что функция c ++ возвращает, когда в функции не выполняется команда возврата? Есть ли какая-либо логика для нее?"Пример:

int cow () {int temp;вернуть темп;}

Если вы не вернете правильный тип или ничего не вернете, компилятор должен пожаловаться. Редактировать: О дерьмо, я только что прочитал ваши флаги.Вам нужно включить больше флагов, -W -Wall -Pedantic.Прочтите руководство по g ++.

Если у вас нет функции void.Тогда вам не нужно ничего возвращать или у вас может быть указатель для воспроизведения.

void somefunction (int * ptr_int) {int temp = * ptr_int;температура + = 1000;this-> ptr_int = temp;}

Я считаю, что приведенный выше код работает, прошло много времени с тех пор, как я написал код на C ++.

0 голосов
/ 11 августа 2010

С современным компилятором вы, вероятно, получите предупреждение, используя -Wall

Но если вы не вернете значение, обычно вы получите мусор.

...