23

Por sugerencia del usuario PaperBirdMaster me he animado ha realizar la pregunta que se indica en el título de este post.

Básicamente, como le comenté a dicho usuario, he visto en diferentes respuestas de SO que en C++ no es necesario incluir la instrucción return 0; en la función main ya que el compilador es capaz de incluir dicha instrucción por su cuenta. ¿Cuánto de cierto hay en la afirmación anterior?

Personalmente, prefiero incluir el return 0; debido a que va en la línea de usar un return dentro de una función, pues por definición las funciones devuelven un valor. Sería distinto si el main lo declarase como void main(), lo cual no es estándar, pero al menos es válido en Visual Studio, por poner un ejemplo, y ahí si no vería la necesidad de incluir algún tipo de return.

Por otro lado, relacionado a todo lo anterior, ¿cuán válido es utilizar otro tipo de return como, por ejemplo, return EXIT_SUCCESS;, que se puede encontrar en uno de los libros sobre C++ de Luis Joyanes.

Gracias de antemano por sus respuestas y/o comentarios.

Xam
  • 834
  • 3
  • 13
  • 21
  • El return 0 se utiliza para ver que tu programa se ejecuto correctamente ya que si todo salio bien regresara un 0 y si hay algun error te regresara cualquier otra cosa menos 0, es por eso que se utiliza – R. Nuñez Feb 19 '18 at 17:21
  • si pero yo me pregunto mas específicamente ¿qué hace el sistema operativo con ese número? – juanda12-18 Aug 23 '20 at 19:15
  • Ese el *código de retorno* (return code) de la aplicación. Un cero generalmente indica que la app. fue exitosa. Cualquier otro valor implica un error o excepción que se debe estudiar caso a caso. El código está disponible para consulta por consola o dentro de un batch. – Candid Moe Aug 23 '20 at 19:28

4 Answers4

18

¿Cuánto de cierto hay en la afirmación anterior?

Atendiendo al draft de C++14, en la sección 3.6.1 Encontramos lo siguiente:

5 A return statement in main has the effect of leaving the main function (destroying any objects with automatic storage duration) and calling std::exit with the return value as the argument. If control reaches the end of main without encountering a return statement, the effect is that of executing

return 0;

Que viene a decir lo siguiente :

La instrucción return provoca que la ejecución abandone la función main (los objetos que se salgan de ámbito serán eliminados). Además se llamará a std::exit con el valor usado en el return como argumento. Si la función main finaliza sin una instrucción return se ejecutará la instrucción:

return 0;

Así que la respuesta es NO, no es obligatorio incluir la instrucción return en la función main.

Sí será obligatorio añadir esta instrucción cuando la aplicación necesite devolver diferentes valores en función del resultado de la ejecución (por ejemplo para indicar errores).

Sería distinto si el main lo declarase como void main(), lo cual no es estándar, pero al menos es válido en Visual Studio, por poner un ejemplo, y ahí si no vería la necesidad de incluir algún tipo de return.

Si leemos el apartado 2 de la sección antes comentada (3.6.1):

2 An implementation shall not predefine the main function. This function shall not be overloaded. It shall have a return type of type int, but otherwise its type is implementation-defined. All implementations shall allow both.

Que básicamente viene a decir que la función main debe devolver un tipo int. Por supuesto que, por cuestiones de compatibilidad, hay compiladores que tragan con void... pero cuidado con esto porque nada te garantiza que la siguiente versión del compilador vaya a aceptar tanto esa como otras tantas licencias... puedes encontrarte con la situación de tener que editar decenas de líneas de código solo para que el programa vuelva a compilar.

cuán válido es utilizar otro tipo de return como, por ejemplo, return EXIT_SUCCESS;, que se puede encontrar en uno de los libros sobre C++ de Luis Joyanes.

EXIT_SUCCESS no es un tipo sino que es una constante:

#define EXIT_SUCCESS 0

Y está disponible tanto para C como para C++ a través de las librerías stdlib.h o cstdlib.

Por tanto, EXIT_SUCCESS es, en tu caso, equivalente a poner return 0;.

Entonces, ¿Por qué usar EXIT_SUCCESS si se escribe más?

Bueno, piensa que tanto C como C++ no se han diseñado para una arquitectura en concreto... si te encuentras con un Sistema Operativo en el que una aplicación debe devolver un valor diferente de 0 cuando finaliza correctamente la macro se adaptará sin problemas mientras que el 0 te tocará modificarlo a mano.

eferion
  • 49,291
  • 5
  • 30
  • 72
  • He encontrado el siguiente enlace para [c++17](http://en.cppreference.com/w/cpp/language/main_function), ya que la web de ISO obliga a pagar para descargar el estándar. Dice que si no hay un return, se asume un `return 0;` al final del flujo – Pablo Lozano Feb 19 '18 at 17:29
  • @PabloLozano es algo que no ha cambiado en el estándar – eferion Feb 19 '18 at 17:35
  • lo comentaba simplemente para completar tu respuesta, ya que explícitamente nombras c++14 – Pablo Lozano Feb 19 '18 at 17:48
  • @PabloLozano nombro c++14 porque es el mas reciente con permiso de c++17 (que aun le falta extenderse un poco). Podría haber cogido cualquier otro estándar y diría exactamente lo mismo... pero este es el más actual. No tiene demasiado sentido regirse por estándares antiguos salvo que no haya más remedio – eferion Feb 19 '18 at 19:24
  • 2
    @PabloLozano puedes encontrar el borrador más reciente (y gratuito) del estándar de C++ en [isocpp](https://isocpp.org/std). – PaperBirdMaster Feb 19 '18 at 20:26
13

He visto [...] que en C++ no es necesario incluir la instrucción return 0; en la función main ya que el compilador es capaz de incluir dicha instrucción por su cuenta. ¿Cuánto de cierto hay en la afirmación anterior?

Es cierto, con matices.

  1. Es necesario retornar un valor en funciones que retornen valores o se incurrirá en comportamiento indefinido... excepto en el caso de main, cuyo comportamiento está definido.
  2. El compilador no incluirá ninguna instrucción return excepto en el caso de main, pero lo hace para seguir el estándar, no porque sea una decisión que el compilador tome a su libre albedrío.

En el estándar de C++ el texto relevante sobre el primer punto es (traducción y resaltado mío):

9.6.3.2 La instrucción return.

La expresión-o-lista-entre-llaves de una instrucción return recibe el nombre de operando. Una instrucción return sin operando debe ser usada sólo en funciones cuyo tipo es void constante o volátil, un constructor o un destructor. Una instrucción return con cualquier otro operando sebe ser usada sólo en una función cuyo tipo de retorno no sea void constante o volátil; [...] llegar al final de un constructor, destructor, o función con tipo de retorno void constante o volátil es equivalente a una instrucción return sin operando. En cualquier otro caso, llegar al final de una función diferente a main resulta en comportamiento indefinido.

El texto relevante sobre el segundo punto es (traducción y resaltado mío):

6.6.1.5

Una instrucción return en main tiene como efecto abandonar la función main (destruyendo cualquier objeto con duración de almacenamiento automática) y llamar std::exit con el valor de la instrucción return como argumento. Si el control abandona la declaración de main, el efecto es equivalente a llamar la instrucción return con operando 0.


Conclusión.

Si bien es cierto que un compilador de C++ que siga el estándar se comporta de manera definida en funciones main sin instrucción return, yo (personalmente) me opongo a ello por los siguientes motivos:

  • Denota intencionalidad: Escribir explícitamente la instrucción de retorno, muestra la intencionalidad del programador; si se deja que lo haga de manera automática queda la duda de si es una omisión accidental o intencionada1.
  • Homogeniza el código: es perturbador el seguir unas normas determinadas y estrictas para todas las funciones del código excepto para una. Si además la función main tuviese otros retornos explícitos, sería aún más perturbador confiar en un return implícito mientras los otros no lo han sido1.
  • Sigue el principio de mínima sorpresa: Si una función tiene un retorno, lo sorprendente sería que no retornase nada (al menos de manera visiblemente explícita).

  1. Podría añadirse un comentario al final de main para mostrar esa intencionalidad:

    int main() {
        try {
            run();
        } catch (const std::exception &) {
            return 1;
        }
        /* devolvemos 0 de manera automatica segun se establece
           en el punto 6.6.1.5 del estandar del lenguaje. */
    }
    

    Pero ¡es mucho más sencillo simplemente escribir la instrucción return adecuada!.

PaperBirdMaster
  • 44,474
  • 6
  • 44
  • 82
  • Su respuesta y la del usuario eferion son muy buenas, pero al final me voy a decantar por la otra respuesta. De todos modos, gracias por animarme a realizar la pregunta y también por haberla respondido. – Xam Feb 20 '18 at 06:06
  • La respuesta de eferion es objetivamente más completa. Mi respuesta contiene lo mismo pero añade una valoración personal. – PaperBirdMaster Feb 20 '18 at 07:38
0

Explicando este tema de la instrucción "return 0;"; esta lo que hace es finalizar una función y devolver el control a donde se llamó la función. Por ejemplo: En el caso de un simple programa de C++ que escribe "Hola Mundo"; lo que hace esta instrucción es finalizar "main" y devolverle el control al sistema operacional de nuestra máquina; el valor 0 le dice al sistema operacional que el programa ha finalizado correctamente. Segun la última versión de C++; este return 0 puede omitirse y el programa trabajará normalmente!.

MiSCapu
  • 66
  • 11
0

Comprendo los argumentos y las buenas prácticas de programación. Pero saliendo de convención podrías retornarle un 99 y tendría sentido sólo para tí, manipulando el main desde alguna consola y accediendo a ese valor de retorno.

  • Cualquier salida que no sea 0 solo va a tener sentido para aquel que conozca las posibles salidas del programa. El mecanismo por defecto tratará cualquier salida distinta de 0 como un error genérico – eferion Aug 24 '20 at 06:40