¿Hay alguna diferencia entre return n
(en la main
función) y exit(n)
en C? ¿Está definido por los estándares C o POSIX o depende del sistema operativo o del compilador?
En la mayoría de los casos, no hay diferencia, pero aquí hay un programa en C que probablemente se comportará de manera diferente dependiendo de si usa return 0;
o exit(0);
:
#include <stdio.h>
#include <stdlib.h>
static char *message;
void cleanup(void) {
printf("message = \"%s\"\n", message);
}
int main(void) {
char local_message[] = "hello, world";
message = local_message;
atexit(cleanup);
#ifdef USE_EXIT
puts("exit(0);");
exit(0);
#else
puts("return 0;");
return 0;
#endif
}
Debido a la atexit()
llamada, exit(0);
o return 0;
hace cleanup
que se invoque la función. La diferencia es que si el programa llama exit(0);
, la limpieza ocurre mientras la "llamada" a main()
todavía está activa, por lo que el local_message
objeto todavía existe. return 0;
Sin embargo, la ejecución finaliza inmediatamente la invocación de main()
y luego invoca la cleanup()
función. Como se cleanup()
refiere (a través del message
puntero global ) a un objeto asignado localmente main
y ese objeto ya no existe, el comportamiento no está definido.
Aquí está el comportamiento que veo en mi sistema:
$ gcc -DUSE_EXIT c.c -o c && ./c
exit(0);
message = "hello, world"
$ gcc c.c -o c && ./c
return 0;
message = ""
$
Ejecutar el programa sin -DUSE_EXIT
podría hacer nada, incluso bloquearse o imprimir "hello, world"
(si la memoria utilizada por local_message
no se golpea).
Sin embargo, en la práctica, esta diferencia solo se muestra si los objetos definidos localmente en el interior main()
se hacen visibles main()
al guardarlos apuntadores. Esto podría suceder plausiblemente argv
. (El experimento en mi sistema muestra que los objetos señalados por argv
y por *argv
seguir existiendo después de regresar main()
, pero no debe depender de eso).
Para C,
el Estándar dice que un retorno de la llamada inicial a main es equivalente a llamar a exit. Sin embargo, no se puede esperar que un retorno de main funcione si los datos locales a main pueden ser necesarios durante la limpieza.
Para C ++
Cuando se usa exit (0) para salir del programa, no se llama a los destructores de objetos no estáticos con ámbito local. Pero se llama a los destructores si se usa el retorno 0.
Programa 1 - - usa la salida (0) para salir
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
class Test {
public:
Test() {
printf("Inside Test's Constructor\n");
}
~Test(){
printf("Inside Test's Destructor");
getchar();
}
};
int main() {
Test t1;
// using exit(0) to exit from main
exit(0);
}
Salida: Constructor de prueba interior
Programa 2: utiliza el retorno 0 para salir
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
class Test {
public:
Test() {
printf("Inside Test's Constructor\n");
}
~Test(){
printf("Inside Test's Destructor");
}
};
int main() {
Test t1;
// using return 0 to exit from main
return 0;
}
Salida: Constructor de
prueba interna Destructor de prueba interna
Llamar a los destructores a veces es importante, por ejemplo, si el destructor tiene código para liberar recursos como cerrar archivos.
Tenga en cuenta que los objetos estáticos se limpiarán incluso si llamamos a exit (). Por ejemplo, vea el siguiente programa.
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
class Test {
public:
Test() {
printf("Inside Test's Constructor\n");
}
~Test(){
printf("Inside Test's Destructor");
getchar();
}
};
int main() {
static Test t1; // Note that t1 is static
exit(0);
}
Salida: Constructor de
prueba interna Destructor de prueba interna
finally
Vale la pena señalar que el estándar C (C99) define dos tipos de entornos de ejecución, Entorno independiente y Entorno hospedado . El entorno independiente es un entorno C que no admite las bibliotecas C y está destinado a aplicaciones integradas y similares. El entorno de CA que admite las bibliotecas C se denomina entorno hospedado.
C99 dice que, en un entorno independiente, la terminación del programa se define como implementación. Entonces, si la implementación define
main
,return n
yexit
, sus comportamientos son como se define en esa implementación.C99 define el comportamiento del entorno alojado como,
fuente
Desde la perspectiva del estándar C, no realmente, aparte de
return
ser una declaración yexit()
una función. Cualquiera de las dos haráatexit()
que se llame a cualquier función registrada, seguida de la finalización del programa.Hay un par de situaciones que debes tener en cuenta:
main()
. Aunque rara vez se ve en la práctica, es legal en C. (C ++ lo prohíbe explícitamente).main()
. A veces, un existentemain()
cambiará de nombre y se llamará por uno nuevomain()
.El uso de
exit()
introducirá un error si cualquiera de esos ocurre después de que haya escrito el código, especialmente si no termina de manera anormal. Para evitar eso, es una buena idea tener el hábito de tratarlomain()
como la función que es y usarloreturn
cuando desee que termine.fuente