Инструкция return почему возвращает 0 от чего зависит возвращаемое значение

If, in your code, you say that your function returns a value, but you don’t actually return one:

int my_function(int x)
{
    // bad practice!
}

… that is an error bad practice. You said that you were going to return a value (in this case, an ‘int’) but you did not.

Similarly, if there are multiple paths through your function:

int my_function(int x)
{
    if (x == 3)
        return 42;  // good

    // bad!
}

and you’ve again declared the intent to return a value, but some paths through your function do not, that is also an error bad practice; you have broken your promise to the callers of your function.

All paths through a function should end up at a return statement:

int my_function(int x)
{
    if (x == 3)
        return 42;  // good

    return 1;  // good
}

If you don’t want to return any values, then declare the function void:

void my_function(int x)
{
    // good
}

UPDATE: above, you may notice that I replaced «an error» with «bad practice». That’s because the word ‘error’ means something very particular within the C standard, and forgetting a return statement doesn’t meet that definition (instead, it’s considered to be «undefined behavior,» and your compiler might not even complain.) However, you as a human being should consider it an error in your code, and avoid forgetting return statements on all exit paths out of your functions.

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

Далее предстоит разобраться с принципами работы функции return в C++. Эта информация пригодится преимущественно начинающим разработчикам.

Описание функции возврата

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

В C++ и C имеются операторы возврата. Они называются функциями перехода. Используются для возврата значений или остановки выполнения операции. Называется оператор перехода return (ретурном).

При обработке return происходит следующее:

  1. Выполнение имеющейся функции прекращается.
  2. Управление переходит обратно в точку вызова обработанной операции.
  3. Инструкции, написанные после return, никогда не выполняются.
  4. Если внутри функции отсутствует соответствующий оператор, при достижении закрывающейся фигурной скобки управление передается в точку вызова обработанной операции. Возвращаемое значение не определяется.

Операторы return имеются несколько сценариев использования. Всего их два. Далее они будут рассмотрены более подробно.

Использование внутри основной функции

Это – первый метод применения returning. Он делает следующее:

  1. Return останавливает исполнение программы. Происходит присваивание значения 0 (zero) или 1 (one). Они указываются на статус выполнения.
  2. Соответствующие коды использовались в C в виде соглашения. Связано это с отсутствием поддержки объектов, классов и исключений непосредственно в языке.
  3. Return 0 возвращает функции 0. Данная запись указывает на успешное выполнение заданных операций. Функция обработана так, как было задумано изначально.
  4. Return 1 возвращает 1. Указывает на наличие ошибки или сбоя при выполнении приложения. Данная запись свидетельствует о том, что функция не работает по задуманному предназначению.

Что делает returned 0, понятно. Стоит обратить внимание на то, что операционные системы могут самостоятельно завершать приложения с определенными кодами статуса выхода. Это возможно тогда, когда выполняется некоторый спектр недопустимых операций. А еще в зависимости от операционной системы на устройстве пользователя могут меняться соглашения о кодах возврата. Это достаточно редкая ситуация.

Внутри пользовательских функций

Второй вариант использования returns в программном коде – это внутри пользовательских функций. В C++ данный подход широко используется на практике. Соответствующий язык программирования рассматривает логическое значение в качестве отдельного типа данных с двумя «исходами» — истина (true) и ложь (false).

Значения 0 и 1 являются целочисленными (тип int). Они не могут быть неявно преобразованы в логические. Это приводит к тому, что:

  • return 0 делает возврат false из заданной инструкции;
  • return 1 возвращает истину.

Необходимо помнить, что не всегда returns применяются с 0 и 1. Далее предстоит рассмотреть наглядный пример с отличающимся возвращаемым параметром.

Принцип работы – пример

Чтобы лучше разбираться в операторах перехода в C++, рекомендуется рассмотреть принцип их работы на наглядном примере. Необходимо написать приложение, которое будет запрашивать у клиента число, а затем выводить его квадрат. Для уточнения «цифры» используется отдельная инструкция. Ее предстоит создать самостоятельно.

Делается это так:

  1. Сначала требуется создать функцию, которая запрашивает число на вывод с консоли:.
  2. Во второй строке создается функция типа int под названием EnterNumer.
  3. Строки 3-6 используются для описания инструкций, выполняемых после вызова функции. Сначала клиенту на экране предлагается ввод целого числа. Далее программа создает переменную для него и получит заданный параметр.
  4. Описанная функция вызывается из главной (main): .
  5. Функция, запрашивающая и получающая число, вызвана. По завершению работы она должна вернуть в main число, которое было указано пользователем. Эта операция прописана в 7 строке кода. После его обработки произойдет возврат переменной int. Поэтому инструкция выглядит как return input: .
  6. Чтобы сохранить значения, необходимо воспользоваться переменной. Она инициализируется функцией EnterNumber(). Это происходит в строке 11: .
  7. Соответствующая инструкция указывает на то, что в памяти резервируется место для переменной с именем num типа int. Далее происходит инициализация ее значением, возвращенным из функции EnterNumber. Предварительно запускается выполнение предусматриваемых инструкций.
  8. Необходимо завершить приложение выводом на дисплей квадрата числа, полученного из функции EnterNumber(). Для этого используется std::cout:.

При обработке соответствующего кода на экране появится такой результат:

Мы сделали программу, которая использует return. Он используется для возврата значений. Но соответствующий оператор может ничего не возвращать.

Тип void

Тип функции void в C++ — это ничего или пустота. Он указывает компилятору на то, что соответствующая команда не возвращает никаких параметров. Если в ее конце устанавливается оператор return, программа просто не пройдет стадию компиляции.

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

Написанное приложение печатает две строчки текста, хранимых в двух «алгоритмах» типа void. Они ничего не вернут – только выполняют заданные инструкции. После этого происходит после обращения к ним main().

Как быстрее разобраться с темой

Операторы перехода в C++ – это не так трудно, как кажется. Чтобы надписи типа return, include, main и другие не вызывали вопросов, рекомендуется пройти дистанционные компьютерные курсы. На них с нуля пользователей научат разрабатывать приложения на разных языках – от Python до C++.

Пример – от образовательного центра OTUS. Пользователя в срок до 12 месяцев научат основам разработки. Люди смогут освоить любую IT-профессию. В процессе обучения гарантируется постоянное кураторство, много практики, а также интересные домашние задания. Ученику помогут составить портфолио. В конце курса выдается электронный сертификат, который подтверждает приобретенный спектр навыков и знаний.

Хотите освоить современную IT-специальность? Огромный выбор курсов по востребованным IT-направлениям есть в Otus! Ниже – один из них:

I need the simplest possible answer to this. I have looked up in various sites for the answer. If the inputs to a programme is such that the output is 10, will command return 0 force the programme to return the value 0 instead of 10? I have written simple C programmes on Borland IDE without return 0 and they work fine.

asked Jan 4, 2014 at 10:27

ThePhysicist's user avatar

1

Nothing to add to Maroun’s link. That’s the way if you want to know more about return values.

Just a few words for a novice:

int main()
{
  return 0;
}

and

int main()
{
  return 22;
}

and

void main()
{

}

will all behave the same way if you’re not checking the return value for a program and compile on most default-set compilers.

When you execute a program on the command line (windows) or shell (linux), you can check whether that program failed or completed its tasks successfully by checking the return value, that is, exactly that value you’re returning.

Following the standard is a good habit by the way, and I therefore strongly recommend it to you.

answered Jan 4, 2014 at 10:32

Marco A.'s user avatar

Marco A.Marco A.

43k26 gold badges131 silver badges245 bronze badges

I assume you’re talking about the main() function: If you return anything else than 0 (which is the same as omitting return altogether) this is assumed to be an error code, and can be used to notify other programs that the current program failed to do what it is supposed to do.

answered Jan 4, 2014 at 10:32

Njol's user avatar

NjolNjol

3,27117 silver badges32 bronze badges

The main function is generally supposed to return a value and after it returns something it finishes execution.The return 0 means success and returning a non-zero number means failure. Thus we «return 0» at the end of main function. But you can run the main function without the return 0.It works the same . Sources :
What is the proper declaration of main?

Community's user avatar

answered Jan 4, 2014 at 10:33

Sunil Kumar's user avatar

Sunil KumarSunil Kumar

5,9926 gold badges35 silver badges40 bronze badges

The return code of the main function is passed back to the operating system. What it does with this depends. If you execute a program on the commandline you can simply ignore it. In scripts this returncode can be used to determine how to proceed.

If you use void main() it will return 0.

Here is an example for DOS:

rem test.bat
@echo off
MainReturnValTest
@if "%ERRORLEVEL%" == "0" goto good
:fail
    echo Execution Failed
    echo return value = %ERRORLEVEL%
    goto end

:good
    echo Execution succeeded
    echo Return value = %ERRORLEVEL%
    goto end

:end

The same can of course be done on other OSes using different syntax. For example in Linux you could use:

myprogram && echo success

which would only print success if the returncode was 0.

The operation of your program is not affected of course.

answered Jan 4, 2014 at 10:42

Devolus's user avatar

DevolusDevolus

21.6k13 gold badges66 silver badges113 bronze badges

  1. The return value has nothing to do with your Output value . That is, even if your output is 10, you return 0.
  2. Every command returns an exit status (sometimes referred to as a return status or exit code). A successful command returns a 0, while an unsuccessful one returns a non-zero value that usually can be interpreted as an error code. Well-behaved UNIX commands, programs, and utilities return a 0 exit code upon successful completion, though there are some exceptions.

answered Jan 4, 2014 at 10:52

Parag Gangil's user avatar

Parag GangilParag Gangil

1,2082 gold badges12 silver badges27 bronze badges

Добавлено 9 апреля 2021 в 22:58

Рассмотрим следующую программу:

#include <iostream>
 
int main()
{
	// получаем значение от пользователя
	std::cout << "Enter an integer: ";
	int num{};
	std::cin >> num;
 
	// выводим удвоенное значение
	std::cout << num << " doubled is: " << num * 2 << 'n';
 
	return 0;
}

Эта программа состоит из двух концептуальных частей: во-первых, мы получаем значение от пользователя. Затем мы сообщаем пользователю, чему равно это значение, умноженное на два.

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

Итак, давайте напишем программу для этого:

// Эта программа не работает
#include <iostream>
 
void getValueFromUser()
{
 	std::cout << "Enter an integer: ";
	int input{};
	std::cin >> input;  
}
 
int main()
{
	getValueFromUser(); // Просим пользователя ввести данные
 
	int num{}; // Как нам получить значение из getValueFromUser() 
               // и использовать его для инициализации этой переменной??
 
	std::cout << num << " doubled is: " << num * 2 << 'n';
 
	return 0;
}

Хотя эта программа – хорошая попытка решения, она не совсем работает.

Когда вызывается функция getValueFromUser, пользователя просят ввести целое число, как и ожидалось. Но введенное им значение теряется, когда getValueFromUser завершает работу и управление возвращается к main. Переменная num никогда не инициализируется значением, введенным пользователем, поэтому программа всегда печатает ответ 0.

Чего нам не хватает, так это того, чтобы getValueFromUser могла вернуть значение, введенное пользователем, обратно в main, чтобы main могла использовать эти данные.

Возвращаемые значения

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

Во-первых, ваша функция должна указать, значение какого типа будет возвращено. Это делается путем установки типа возвращаемого значения функции, который является типом, определенным перед именем функции. В приведенном выше примере функция getValueFromUser имеет тип возвращаемого значения void, а функция main имеет тип возвращаемого значения int. Обратите внимание, что это не определяет, какое конкретное значение будет возвращено – только тип значения.

Во-вторых, внутри функции, которая будет возвращать значение, мы используем инструкцию return, чтобы указать конкретное значение, возвращаемое вызывающей стороне. Конкретное значение, возвращаемое функцией, называется возвращаемым значением. Когда инструкция return выполняется, возвращаемое значение копируется из функции обратно в вызывающую функцию. Этот процесс называется возвратом по значению.

Давайте рассмотрим простую функцию, которая возвращает целочисленное значение, и пример программы, которая ее вызывает:

#include <iostream>
 
// int - это тип возвращаемого значения
// Тип возвращаемого значения int означает, что функция вернет вызывающей стороне
// некоторое целочисленное значение (конкретное значение здесь не указано)
int returnFive()
{
    // инструкция возврата указывает конкретное значение, которое будет возвращено
    return 5; // возвращаем конкретное значение 5 обратно вызывающей стороне
}
 
int main()
{
    std::cout << returnFive() << 'n';     // печатает 5
    std::cout << returnFive() + 2 << 'n'; // печатает 7
 
    returnFive(); // хорошо: значение 5 возвращается, но игнорируется, 
                  // поскольку main() ничего с ним не делает
 
    return 0;
}

При запуске эта программа печатает:

5
7

Выполнение начинается с верхней части main. В первой инструкции вычисляется вызов функции returnFive, в результате чего вызывается функция returnFive. Функция returnFive возвращает конкретное значение 5 обратно вызывающей стороне, которое затем выводится в консоль через std::cout.

Во второй инструкции вычисляется вызов функции returnFive, что приводит к повторному вызову функции returnFive. Функция returnFive возвращает значение 5 обратно вызывающей стороне. Выражение 5 + 2 вычисляется для получения результата 7, который затем выводится в консоль через std::cout.

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

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

Исправляем нашу тестовую программу

Теперь, узнав это, мы можем исправить программу, которую представили в начале урока:

#include <iostream>
 
int getValueFromUser() // эта функция теперь возвращает целочисленное значение
{
 	std::cout << "Enter an integer: ";
	int input{};
	std::cin >> input;  
 
	return input; // возвращаем значение, введенное пользователем, обратно вызывающей функции
}
 
int main()
{
	int num { getValueFromUser() }; // инициализируем num значением, возвращаемым getValueFromUser()
 
	std::cout << num << " doubled is: " << num * 2 << 'n';
 
	return 0;
}

Когда эта программа выполняется, первая инструкция в main создаст переменную типа int с именем num. Когда программа перейдет к инициализации num, она увидит, что есть вызов функции getValueFromUser, поэтому она выполнит эту функцию. Функция getValueFromUser просит пользователя ввести значение, а затем возвращает это значение вызывающей функции (main). Это возвращенное значение используется как значение для инициализации переменной num.

Скомпилируйте эту программу и запустите ее несколько раз, чтобы убедиться, что она работает.

Отсутствие возвращаемого значения

Функции не обязаны возвращать значение. Чтобы сообщить компилятору, что функция не возвращает значение, используется тип возвращаемого значения void. Давайте посмотрим на функцию doPrint() из предыдущего урока:

void doPrint() // void is the return type
{
    std::cout << "In doPrint()" << 'n';
    // Эта функция не возвращает значение, поэтому инструкция return не требуется
}

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

Вот еще один пример функции, ничего не возвращающей, и пример программы, которая ее вызывает:

#include <iostream>
 
// void означает, что функция не возвращает значение вызывающей стороне
void returnNothing()
{
    std::cout << "Hi" << 'n';
    // Эта функция не возвращает значение, поэтому инструкция return не требуется
}
 
int main()
{
    returnNothing(); // хорошо: вызывается функция returnNothing(), значение не возвращается
 
    std::cout << returnNothing(); // ошибка: эта строка не компилируется. 
                                  // Вам нужно будет закомментировать ее, чтобы продолжить.
 
    return 0;
}

При первом вызове функции returnNothing функция печатает «Hi», а затем ничего не возвращает вызывающей функции. Управление возвращается в main, и программа продолжает выполнение.

Второй вызов функции returnNothing даже не будет компилироваться. Функция returnNothing имеет возвращаемый тип void, то есть не возвращает значения. Однако эта инструкция пытается отправить возвращаемое из returnNothing значение в std::cout для печати. std::cout не знает, что с этим делать (какое значение он будет выводить?). Следовательно, компилятор пометит это как ошибку. Вам нужно закомментировать эту строку кода, чтобы код компилировался.

Тип возврата void (что означает, что ничего не возвращается) используется, когда нам нужна функция, которая ничего не возвращает вызывающей стороне (потому что в этом нет необходимости). В приведенном выше примере у функции returnNothing есть полезное поведение (она печатает «Hi»), но ей не нужно ничего возвращать вызывающей стороне (в данном случае main). Следовательно, функции returnNothing присваивается возвращаемый тип void.

Возвращаясь к main

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

По определению, код состояния 0 означает, что программа выполнена успешно.

Лучшая практика


Ваша функция main должна возвращать 0, если программа работает нормально.

Код состояния, отличный от нуля, часто используется для обозначения сбоя (и хотя он отлично работает в большинстве операционных систем, строго говоря, его портируемость не гарантируется).

Для продвинутых читателей


Стандарт C++ определяет значение только трех кодов состояния: 0, EXIT_SUCCESS и EXIT_FAILURE. 0 и EXIT_SUCCESS означают, что программа выполнена успешно. EXIT_FAILURE означает, что программа не была успешно выполнена.

EXIT_SUCCESS и EXIT_FAILURE определены в заголовочном файле <cstdlib>:

#include <cstdlib> // для EXIT_SUCCESS и EXIT_FAILURE
 
int main()
{
    return EXIT_SUCCESS;
}

Если вы хотите максимизировать портируемость, вы должны использовать только 0 или EXIT_SUCCESS, чтобы указать на успешное завершение, или EXIT_FAILURE, чтобы указать на неудачное завершение.

C++ запрещает явный вызов функции main.

На данный момент вы также должны определять свою функцию main внизу исходного файла кода, под другими функциями.

Несколько дополнительных замечаний о возвращаемых значениях

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

Лучшая практика


Всегда явно указывайте возвращаемое значение для любой функции, которая имеет тип возврата не-void.

Предупреждение


Неспособность вернуть значение из функции с типом возврата не-void (кроме main) приведет к неопределенному поведению.

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

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

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

Например:

// Функция просит пользователя ввести значение
// Возвращаемое значение - это целое число, введенное пользователем с клавиатуры
int getValueFromUser()
{
 	std::cout << "Enter an integer: ";
	int input{};
	std::cin >> input;  
 
	return input; // возвращаем значение, введенное пользователем, обратно вызывающей функции
}

Повторное использование функций

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

#include <iostream>
 
int main()
{
	int x{};
	std::cout << "Enter an integer: ";
	std::cin >> x; 
 
	int y{};
	std::cout << "Enter an integer: ";
	std::cin >> y; 
 
	std::cout << x << " + " << y << " = " << x + y << 'n';
 
	return 0;
}

Пока эта программа работает, но она немного избыточна. Фактически, эта программа нарушает один из основных принципов хорошего программирования: «Не повторяйся» (или англоязычная аббревиатура DRY, т.е. «Don’t Repeat Yourself»).

Почему повторяющийся код плох? Если бы мы хотели изменить текст «Enter an integer:» на что-то другое, нам пришлось бы обновить его в двух местах. А что, если бы мы захотели инициализировать 10 переменных вместо 2? Это было бы большое количество избыточного кода (что сделало бы наши программы длиннее и сложнее для понимания) и много места для вкрадывания опечаток.

Давайте обновим эту программу, чтобы использовать нашу функцию getValueFromUser, которую мы разработали выше:

#include <iostream>
 
int getValueFromUser()
{
 	std::cout << "Enter an integer: ";
	int input{};
	std::cin >> input;  
 
	return input;
}
 
int main()
{
    int x{ getValueFromUser() }; // первый вызов getValueFromUser
    int y{ getValueFromUser() }; // второй вызов getValueFromUser
 
    std::cout << x << " + " << y << " = " << x + y << 'n';
 
    return 0;
}

Эта программа создает следующий вывод:

Enter an integer: 5
Enter an integer: 7
5 + 7 = 12

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

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

Лучшая практика


Следуйте рекомендациям DRY: «не повторяйся». Если вам нужно сделать что-то более одного раза, подумайте, как изменить свой код, чтобы удалить как можно больше избыточности. Переменные можно использовать для хранения результатов вычислений, которые необходимо использовать более одного раза (чтобы нам не нужно было повторять вычисления). Функции можно использовать для определения последовательности инструкций, которые мы хотим выполнять более одного раза. А циклы (которые мы рассмотрим в следующей главе) можно использовать для выполнения инструкции более одного раза.

Заключение

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

Функции позволяют минимизировать избыточность наших программ.

Небольшой тест

Вопрос 1

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

1а)

#include <iostream>
 
int return7()
{
    return 7;
}
 
int return9()
{
    return 9;
}
 
int main()
{
    std::cout << return7() + return9() << 'n';
 
    return 0;
}

Ответ

Эта программа печатает число 16.

1b)

#include <iostream>
 
int return7()
{
    return 7;
 
    int return9()
    {
        return 9;
    }
}
 
int main()
{
    std::cout << return7() + return9() << 'n';
 
    return 0;
}

Ответ

Эта программа не компилируется. Вложенные функции не допускаются.

1c)

#include <iostream>
 
int return7()
{
    return 7;
}
 
int return9()
{
    return 9;
}
 
int main()
{
    return7();
    return9();
 
    return 0;
}

Ответ

Эта программа компилируется, но ничего не выводит. Значения, возвращаемые функциями, ни для чего не используются (и, таким образом, отбрасываются).

1d)

#include <iostream>
 
void printA()
{
    std::cout << "An";
}
 
void printB()
{
    std::cout << "Bn";
}
 
int main()
{
    printA();
    printB();
 
    return 0;
}

Ответ

Эта программа печатает буквы A и B в отдельных строках.

1e)

#include <iostream>
 
void printA()
{
    std::cout << "An";
}
 
int main()
{
    std::cout << printA() << 'n';
 
    return 0;
}

Ответ

Эта программа не компилируется. Функция printA() возвращает void, которое main() пытается отправить в std::cout. Это приведет к ошибке компиляции.

1f)

#include <iostream>
 
int getNumbers()
{
    return 5;
    return 7;
}
 
int main()
{
    std::cout << getNumbers() << 'n';
    std::cout << getNumbers() << 'n';
 
    return 0;
}

Ответ

Эта программа напечатает 5 дважды (в отдельных строках). Оба раза, когда вызывается функция getNumbers(), возвращается значение 5. Когда выполняется инструкция return 5;, функция немедленно завершается, поэтому инструкция return 7; никогда не выполняется.

1g)

#include <iostream>
 
int return 5()
{
    return 5;
}
 
int main()
{
    std::cout << return 5() << 'n';
 
    return 0;
}

Ответ

1h) Чуть сложнее.

#include <iostream>
 
int returnFive()
{
    return 5;
}
 
int main()
{
    std::cout << returnFive << 'n';
 
    return 0;
}

Ответ

Эта программа будет скомпилирована, но функция не будет вызвана, потому что при вызове функции отсутствуют круглые скобки. То, что на самом деле будет выведено, зависит от компилятора.


Вопрос 2

Что означает «DRY» и почему это полезно?

Ответ

DRY означает «Don’t Repeat Yourself» (не повторяйся). Это практика, которая включает в себя написание кода таким образом, чтобы минимизировать избыточность. Это делает ваши программы более краткими, менее подверженными ошибкам и более удобными для поддержки.

Теги

C++ / CppLearnCppДля начинающихОбучениеПрограммирование

Terminates the current function and returns the specified value (if any) to the caller.

Contents

  • 1 Syntax
  • 2 Explanation
  • 3 Notes
    • 3.1 Automatic move from local variables and parameters
    • 3.2 Guaranteed copy elision
  • 4 Keywords
  • 5 Example
  • 6 Defect reports
  • 7 See also

[edit] Syntax

attr (optional) return expression (optional) ; (1)
attr (optional) return braced-init-list ; (2) (since C++11)
attr (optional) co_return expression (optional) ; (3) (since C++20)
attr (optional) co_return braced-init-list ; (4) (since C++20)
attr (since C++11) sequence of any number of attributes
expression expression, convertible to the function return type
braced-init-list brace-enclosed list of initializers and other braced-init-lists

[edit] Explanation

1) Evaluates the expression, terminates the current function and returns the result of the expression to the caller, after implicit conversion to the function return type. The expression is optional in functions whose return type is (possibly cv-qualified) void, and disallowed in constructors and in destructors.

3,4) In a coroutine, the keyword co_return must be used instead of return for the final suspension point (see coroutines for details).

There is a sequence point between the copy-initialization of the result of the function call and the destruction of all temporaries at the end of expression.

(until C++11)

The copy-initialization of the result of the function call is sequenced-before the destruction of all temporaries at the end of expression, which, in turn, is sequenced-before the destruction of local variables of the block enclosing the return statement.

(since C++11)

[edit] Notes

If control reaches the end of

  • a function with the return type (possibly cv-qualified) void,
  • a constructor,
  • a destructor, or
  • a function-try-block for a function with the return type (possibly cv-qualified) void

without encountering a return statement, return; is executed.

If control reaches the end of the main function, return 0; is executed.

Flowing off the end of a value-returning function (except main) without a return statement is undefined behavior.

In a function returning (possibly cv-qualified) void, the return statement with expression can be used, if the expression type is (possibly cv-qualified) void.

If the return type of a function is specified as a placeholder type, it will be deduced from the return value.

(since C++14)

Returning by value may involve construction and copy/move of a temporary object, unless copy elision is used. Specifically, the conditions for copy/move are as follows:

Automatic move from local variables and parameters

The expression is move-eligible if it is a (possibly parenthesized) id-expression that names a variable of automatic storage duration whose type is

  • a non-volatile object type
  • or a non-volatile rvalue reference to object type
(since C++20)

and that variable is declared

  • in the body or
  • as a parameter of
the innermost enclosing function or lambda expression.

If the expression is move-eligible, overload resolution to select the constructor to use for initialization of the returned value or, for co_return, to select the overload of promise.return_value() (since C++20) is performed twice:

  • first as if expression were an rvalue expression (thus it may select the move constructor), and
  • if the first overload resolution failed or
  • it succeeded, but did not select the move constructor (formally, the first parameter of the selected constructor was not an rvalue reference to the (possibly cv-qualified) type of expression)
(until C++20)
  • then overload resolution is performed as usual, with expression considered as an lvalue (so it may select the copy constructor).
(until C++23)

If the expression is move-eligible, it is treated as an xvalue (thus overload resolution may select the move constructor).

(since C++23)
(since C++11)

Guaranteed copy elision

If expression is a prvalue, the result object is initialized directly by that expression. This does not involve a copy or move constructor when the types match (see copy elision).

(since C++17)
Feature-test macro Value Std Comment
__cpp_implicit_move 202207L (C++23) Simpler implicit move

[edit] Keywords

return,
co_return

[edit] Example

#include <iostream>
#include <string>
#include <utility>
 
void fa(int i)
{
    if (i == 2)
        return;
    std::cout << "fa("<< i << ")n";
} // implied return;
 
int fb(int i)
{
    if (i > 4)
        return 4;
    std::cout << "fb(" << i << ")n";
    return 2;
}
 
std::pair<std::string, int> fc(const char* p, int x)
{
    return {p, x};
}
 
void fd()
{
    return fa(10); // fa(10) is a void expression
}
 
int main()
{
    fa(1); // prints its argument, then returns
    fa(2); // does nothing when i == 2, just returns
 
    int i = fb(5); // returns 4
    i = fb(i);     // prints its argument, returns 2
    std::cout << "i = " << i << 'n'
              << "fc(~).second = " << fc("Hello", 7).second << 'n';
 
    fd();
}

Output:

fa(1)
fb(4)
i = 2
fc(~).second = 7
fa(10)

[edit] Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
CWG 1541 C++98 expression could not be omitted if the return type is cv-qualified void it can be omitted
CWG 1579 C++11 return by converting move constructor was not allowed converting move
constructor lookup enabled
CWG 1885 C++98 sequencing of the destruction of automatic variables was not explicit sequencing rules added

[edit] See also

  • copy elision

Понравилась статья? Поделить с друзьями:
  • Инструкция renault sandero stepway 2
  • Инструкция remote dog training collar инструкция на русском
  • Инструкция remo hobby s max
  • Инструкция rdu 1a выносной дисплей по эксплуатации
  • Инструкция rcd 310 на русском