¿Cuál es la forma correcta (más eficiente) de definir la main()
función en C y C ++ - int main()
o void main()
- y por qué? Si int main()
entonces return 1
o return 0
?
Existen numerosos duplicados de esta pregunta, que incluyen:
- ¿Cuáles son las firmas válidas para la
main()
función de C ? - El tipo de
main()
función de retorno - Diferencia entre
void main()
yint main()
? main()
Firma en C ++- ¿Cuál es la declaración adecuada de
main()
? - Para C ++, con una muy buena respuesta. - Estilos de
main()
funciones en C - Tipo de
main()
método de retorno en C int main()
vsvoid main()
en C
Relacionado:
- C ++ -
int main(int argc, char **argv)
- C ++ -
int main(int argc, char *argv[])
- Es
char *envp[]
como un tercer argumento paramain()
portátil? - ¿Debe la
int main()
función devolver un valor en todos los compiladores? - ¿Por qué se
main()
deja que el usuario defina el tipo de la función en C y C ++? - ¿Por qué
int main(){}
compila? - Definiciones legales de
main()
en C ++ 14?
c++
c
return-value
main
return-type
Joel
fuente
fuente
main
se llama una vez (y en C ++ solo se puede llamar una vez: sin recursión). Si no desea que la ejecución pase mucho tiempomain
, no invoque el programa muchas veces: haga que el programa implemente la repetición.#include
declaracionesreturn
enmain(...)
en un dispositivo integrado, el sistema entra en un estado impredecible y la lavadora se convertirá en consciente de sí mismo y tratar de matar. Entonces, usamosvoid main()
en ese caso. Esta es una práctica estándar de la industria en incrustado de metal desnudo.Respuestas:
El valor de retorno de
main
indica cómo salió el programa. La salida normal está representada por un valor de retorno 0 desdemain
. La salida anormal se indica mediante un retorno distinto de cero, pero no existe un estándar sobre cómo se interpretan los códigos distintos de cero. Como han señalado otros,void main()
está prohibido por el estándar C ++ y no debe usarse. Lasmain
firmas válidas de C ++ son:y
que es equivalente a
También vale la pena señalar que en C ++,
int main()
puede dejarse sin una declaración de retorno, en cuyo punto el valor predeterminado es devolver 0. Esto también es cierto con un programa C99. Sireturn 0;
debe omitirse o no, está abierto a debate. El rango de firmas principales del programa C válido es mucho mayor.La eficiencia no es un problema con la
main
función. Solo se puede ingresar y dejar una vez (marcando el inicio y la finalización del programa) de acuerdo con el estándar C ++. Para C, el reingresomain()
está permitido, pero debe evitarse.fuente
La respuesta aceptada parece estar dirigida a C ++, por lo que pensé en agregar una respuesta que pertenezca a C, y esto difiere en algunas formas.
ISO / IEC 9899: 1989 (C90):
main()
debe declararse como:O equivalente. Por ejemplo,
int main(int argc, char *argv[])
es equivalente al segundo. Además, elint
tipo de retorno puede omitirse ya que es un valor predeterminado.Si una implementación lo permite,
main()
puede declararse de otras maneras, pero esto hace que la implementación del programa se defina y ya no sea estrictamente conforme.El estándar define 3 valores para el retorno que son estrictamente conformes (es decir, no se basa en el comportamiento definido por la implementación):
0
yEXIT_SUCCESS
para una terminación exitosa yEXIT_FAILURE
para una terminación fallida. Cualquier otro valor no es estándar y su implementación está definida.main()
debe tener unareturn
declaración explícita al final para evitar un comportamiento indefinido.Finalmente, no hay nada de malo desde el punto de vista estándar con las llamadas
main()
desde un programa.ISO / IEC 9899: 1999 (C99):
Para C99, todo es igual que arriba excepto:
int
tipo de retorno no puede omitirse.main()
. Si lo hace, ymain()
terminado, hay un implícitoreturn 0
.fuente
Estándar C - Entorno alojado
Para un entorno alojado (ese es el normal), el estándar C11 (ISO / IEC 9899: 2011) dice:
Terminación del programa en C99 o C11
El valor devuelto desde
main()
se transmite al 'entorno' de una manera definida por la implementación.Tenga en cuenta que
0
es obligatorio como 'éxito'. Puede usarEXIT_FAILURE
yEXIT_SUCCESS
desde<stdlib.h>
si lo prefiere, pero 0 está bien establecido, y también lo es 1. Vea también Códigos de salida mayores que 255 - ¿posible? .En C89 (y, por lo tanto, en Microsoft C), no hay una declaración sobre lo que sucede si la
main()
función regresa pero no especifica un valor de retorno; Por lo tanto, conduce a un comportamiento indefinido.Standard C ++ - Entorno Hospedado
El estándar C ++ 11 (ISO / IEC 14882: 2011) dice:
El estándar C ++ dice explícitamente "[la función principal] tendrá un tipo de tipo de retorno
int
, pero de lo contrario su tipo está definido por la implementación", y requiere las mismas dos firmas que el estándar C para ser admitido como opciones. Por lo tanto, el estándar C ++ no permite directamente un 'void main ()', aunque no hay nada que pueda hacer para detener una implementación no estándar que permita alternativas. Tenga en cuenta que C ++ prohíbe que el usuario llamemain
(pero el estándar C no).Hay un párrafo de §18.5 Inicio y terminación en el estándar C ++ 11 que es idéntico al párrafo de §7.22.4.4 La
exit
función en el estándar C11 (citado anteriormente), aparte de una nota al pie (que simplemente documenta queEXIT_SUCCESS
yEXIT_FAILURE
está definido en<cstdlib>
).Estándar C - Extensión común
Clásicamente, los sistemas Unix admiten una tercera variante:
El tercer argumento es una lista de punteros a cadenas con terminación nula, cada una de las cuales es una variable de entorno que tiene un nombre, un signo de igual y un valor (posiblemente vacío). Si no usa esto, aún puede acceder al medio ambiente a través de '
extern char **environ;
'. Esta variable global es única entre aquellos en POSIX en que no tiene un encabezado que la declare.El estándar C reconoce esto como una extensión común, documentada en el Anexo J:
Microsoft C
El compilador de Microsoft VS 2010 es interesante. El sitio web dice:
No me queda claro qué sucede (qué código de salida se devuelve al padre o al SO) cuando un programa con
void main()
sale, y el sitio web de MS también permanece en silencio.Curiosamente, MS no prescribe la versión de dos argumentos
main()
que requieren los estándares C y C ++. Solo prescribe una forma de tres argumentos donde el tercer argumento eschar **envp
, un puntero a una lista de variables de entorno.La página de Microsoft también enumera algunas otras alternativas:
wmain()
que requieren cadenas de caracteres anchas y algunas más.La versión de Microsoft Visual Studio 2005 de esta página no aparece
void main()
como alternativa. Las versiones de Microsoft Visual Studio 2008 en adelante sí.Estándar C - Entorno independiente
Como se señaló anteriormente, los requisitos anteriores se aplican a los entornos alojados. Si está trabajando con un entorno independiente (que es la alternativa a un entorno alojado), entonces el estándar tiene mucho menos que decir. Para un entorno independiente, la función llamada al inicio del programa no necesita ser llamada
main
y no hay restricciones en su tipo de retorno. El estándar dice:La referencia cruzada a la cláusula 4 Conformidad se refiere a esto:
Es notable que el único encabezado requerido de un entorno independiente que realmente define cualquier función es
<stdarg.h>
(e incluso esas pueden ser, y a menudo son, solo macros).Estándar C ++ - Entorno independiente
Así como el estándar C reconoce tanto el entorno alojado como el independiente, también lo hace el estándar C ++. (Citas de ISO / IEC 14882: 2011.)
¿Qué pasa con el uso
int main()
en C?El estándar §5.1.2.2.1 del estándar C11 muestra la notación preferida
int main(void)
- pero también hay dos ejemplos en el estándar que muestranint main()
: §6.5.3.4 ¶8 y §6.7.6.3 ¶20 . Ahora, es importante tener en cuenta que los ejemplos no son 'normativos'; son solo ilustrativos. Si hay errores en los ejemplos, no afectan directamente el texto principal del estándar. Dicho esto, son muy indicativos del comportamiento esperado, por lo que si el estándar incluyeint main()
un ejemplo, sugiere queint main()
no está prohibido, incluso si no es la notación preferida.fuente
int main(){ … }
sí especifica que la función no toma argumentos, pero no proporciona un prototipo de función, AFAICT. Porquemain()
eso rara vez es un problema; significa que si tiene llamadas recursivas amain()
, los argumentos no serán verificados. Para otras funciones, es más un problema: realmente necesita un prototipo de alcance cuando se llama a la función para garantizar que los argumentos sean correctos.main()
recursivamente, fuera de lugares como IOCCC. Tengo un programa de prueba que lo hace, principalmente por novedad. Si tieneint i = 0; int main() { if (i++ < 10) main(i, i * i); return 0; }
y compila con GCC y no incluye-Wstrict-prototypes
, se compila limpiamente bajo advertencias estrictas. Si es asímain(void)
, no se compila.Creo que
main()
debería volverEXIT_SUCCESS
oEXIT_FAILURE
. Se definen enstdlib.h
fuente
EXIT_SUCCESS
yEXIT_FAILURE
porque algunos sistemas operativos históricos (¿VMS?) Usaron un número diferente que 0 para denotar el éxito. Es 0 en todas partes hoy en día.exit(EXIT_SUCCESS)
, lo que siempre hacía lo correcto.Tenga en cuenta que los estándares C y C ++ definen dos tipos de implementaciones: independientes y alojadas.
Entorno alojado C90
Formas permitidas 1 :
Comentarios:
Los dos primeros se indican explícitamente como las formas permitidas, los otros están implícitamente permitidos porque C90 permitió "int implícito" para el tipo de retorno y los parámetros de función. No se permite ninguna otra forma.
Entorno independiente C90
Se permite cualquier forma o nombre de main 2 .
Entorno alojado C99
Formas permitidas 3 :
Comentarios:
C99 eliminó "implícito int" para
main()
lo que ya no es válido.Se ha introducido una oración extraña y ambigua "o de alguna otra manera definida por la implementación". Esto puede interpretarse como "los parámetros para
int main()
pueden variar" o como "main puede tener cualquier forma definida por la implementación".Algunos compiladores han elegido interpretar el estándar de la última manera. Podría decirse que no se puede afirmar fácilmente que no se ajustan estrictamente al citar el estándar en sí mismo, ya que es ambiguo.
Sin embargo, permitir formas completamente salvajes de
main()
probablemente no era (?) La intención de esta nueva oración. La lógica de C99 (no normativa) implica que la oración se refiere a parámetros adicionales aint main
4 .Sin embargo, la sección para la finalización del programa de entorno alojado continúa discutiendo sobre el caso donde main no devuelve int 5 . Aunque esa sección no es normativa sobre cómo debe declararse main, definitivamente implica que main podría declararse de una manera completamente definida por la implementación, incluso en sistemas alojados.
Entorno independiente C99
Cualquier forma o nombre de main está permitido 6 .
Entorno alojado C11
Formularios permitidos 7 :
Entorno independiente C11
Se permite cualquier forma o nombre de main 8 .
Tenga en cuenta que
int main()
nunca se incluyó como un formulario válido para ninguna implementación alojada de C en ninguna de las versiones anteriores. En C, a diferencia de C ++,()
y(void)
tienen diferentes significados. La primera es una característica obsoleta que puede eliminarse del idioma. Consulte las instrucciones futuras del lenguaje C11:Entorno alojado C ++ 03
Formularios permitidos 9 :
Comentarios:
Tenga en cuenta el paréntesis vacío en la primera forma. C ++ y C son diferentes en este caso, porque en C ++ esto significa que la función no toma parámetros. Pero en C significa que puede tomar cualquier parámetro.
C ++ 03 entorno independiente
El nombre de la función llamada al inicio está definido por la implementación. Si se nombra
main()
debe seguir los formularios indicados 10 :Entorno alojado C ++ 11
Formularios permitidos 11 :
Comentarios:
El texto del estándar ha sido cambiado pero tiene el mismo significado.
Entorno independiente C ++ 11
El nombre de la función llamada al inicio está definido por la implementación. Si se nombra
main()
debe seguir los formularios 12 establecidos :Referencias
ANSI X3.159-1989 2.1.2.2 Entorno alojado. "Inicio del programa"
ANSI X3.159-1989 2.1.2.1 Entorno independiente:
ISO 9899: 1999 5.1.2.2 Entorno alojado -> 5.1.2.2.1 Inicio del programa
Justificación de la norma internacional - Lenguajes de programación - C, Revisión 5.10. 5.1.2.2 Entorno alojado -> 5.1.2.2.1 Inicio del programa
ISO 9899: 1999 5.1.2.2 Entorno alojado -> 5.1.2.2.3 Finalización del programa
ISO 9899: 1999 5.1.2.1 Entorno independiente
ISO 9899: 2011 5.1.2.2 Entorno alojado -> 5.1.2.2.1 Inicio del programa
Esta sección es idéntica a la C99 citada anteriormente.
ISO 9899: 1999 5.1.2.1 Entorno independiente
Esta sección es idéntica a la C99 citada anteriormente.
ISO 14882: 2003 3.6.1 Función principal
ISO 14882: 2003 3.6.1 Función principal
ISO 14882: 2011 3.6.1 Función principal
ISO 14882: 2011 3.6.1 Función principal
Esta sección es idéntica a la de C ++ 03 mencionada anteriormente.
fuente
int my_startup_function ()
o, ¿int my_startup_function (int argc, char *argv[])
puede tener, por ejemplo,char my_startup_function (long argc, int *argv[])
también una función de inicio? Supongo que no, ¿verdad? Además, ¿no es tan ambiguo también?main()
porque debe usar una de las firmas enumeradas. Me imagino que sería abrumadoramente el más comúnvoid my_startup_function ()
, ya que no tiene sentido regresar del programa en sistemas independientes.main
? Lo siento si esa no es una pregunta inteligente, pero no podía entender el razonamiento detrás.func()
se considera obsoleto, el borrador en sí lo utilizaint main()
en sus propios ejemplos.Devuelve 0 en caso de éxito y distinto de cero por error. Este es el estándar utilizado por las secuencias de comandos UNIX y DOS para averiguar qué sucedió con su programa.
fuente
main()
en C89 y K&R C, los tipos de retorno no especificados tienen por defecto 'int'.Si no escribe una declaración de devolución
int main()
, el cierre{
devolverá 0 de forma predeterminada.return 0
oreturn 1
será recibido por el proceso de los padres. En un shell, entra en una variable de shell, y si está ejecutando su programa desde un shell y no usa esa variable, entonces no necesita preocuparse por el valor de retorno demain()
.Consulte ¿Cómo puedo obtener lo que ha devuelto mi función principal? .
De esta manera puede ver que es la variable la
$?
que recibe el byte menos significativo del valor de retorno demain()
.En las secuencias de comandos Unix y DOS,
return 0
generalmente se devuelven en caso de error y no cero para el error. Este es el estándar utilizado por las secuencias de comandos Unix y DOS para averiguar qué sucedió con su programa y controlar todo el flujo.fuente
$?
no es una variable de entorno; Es una variable de shell predefinida (o incorporada). La diferencia es difícil de detectar, pero si ejecutaenv
(sin ningún argumento), imprime el entorno y$?
no se mostrará en el entorno.{
" debería ser}
. SO no me permitirá hacer una edición tan pequeña.Tenga en cuenta que, aunque devuelva un int, algunos sistemas operativos (Windows) truncan el valor devuelto a un solo byte (0-255).
fuente
unsigned
). Esto es lo mismo en sistemas UNIX con enteros de 32 bits. Pero los shells de estilo UNIX en cualquiera de los sistemas generalmente solo retendrán un número entero de 8 bits sin signo.El sistema operativo puede utilizar el valor de retorno para verificar cómo se cerró el programa.
El valor de retorno 0 generalmente significa OK en la mayoría de los sistemas operativos (en los que puedo pensar de todos modos).
También se puede verificar cuando llama a un proceso usted mismo y ver si el programa salió y terminó correctamente.
Es NO sólo una convención de programación.
fuente
El valor de retorno de
main()
muestra cómo salió el programa. Si el valor de retorno eszero
, significa que la ejecución fue exitosa, mientras que cualquier valor distinto de cero representará que algo salió mal en la ejecución.fuente
Tenía la impresión de que el estándar especifica que main no necesita un valor de retorno ya que un retorno exitoso se basó en el sistema operativo (cero en uno podría ser un éxito o un fracaso en otro), por lo tanto, la ausencia de retorno fue una señal para el compilador para insertar el retorno exitoso en sí.
Sin embargo, generalmente devuelvo 0.
fuente
Devolver 0 debería decirle al programador que el programa ha finalizado con éxito el trabajo.
fuente
main()
normalmente indica que ocurrió un error; devolver 0 indica éxito. Si sus programas siempre fallan, entonces 1 está bien, pero no es la mejor idea.1
demain
está definido por la implementación. Los únicos valores definidos por el lenguaje son0
,EXIT_SUCCESS
(a menudo definidos como0
), yEXIT_FAILURE
. En OpenVMS,return 1;
denota terminación exitosa .Omitir
return 0
Cuando un programa C o C ++ llega al final del
main
compilador, generará automáticamente código para devolver 0, por lo que no es necesario ponerloreturn 0;
explícitamente al final demain
.Nota: cuando hago esta sugerencia, casi siempre es seguida por uno de dos tipos de comentarios: "No lo sabía". o "¡Eso es un mal consejo!" Mi razonamiento es que es seguro y útil confiar en el comportamiento del compilador respaldado explícitamente por el estándar. Para C, desde C99; ver ISO / IEC 9899: 1999 sección 5.1.2.2.3:
Para C ++, desde el primer estándar en 1998; ver ISO / IEC 14882: 1998 sección 3.6.1:
Todas las versiones de ambos estándares desde entonces (C99 y C ++ 98) han mantenido la misma idea. Confiamos en funciones miembro generadas automáticamente en C ++, y pocas personas escriben
return;
declaraciones explícitas al final de unavoid
función. Las razones contra la omisión parecen reducirse a "se ve raro" . Si, como yo, tiene curiosidad sobre la justificación del cambio al estándar C, lea esta pregunta . También tenga en cuenta que a principios de la década de 1990 esto se consideraba "práctica descuidada" porque era un comportamiento indefinido (aunque ampliamente respaldado) en ese momento.Además, las Pautas principales de C ++ contienen múltiples instancias de omisión
return 0;
al final demain
y ninguna instancia en la que se escriba un retorno explícito. Aunque todavía no hay una directriz específica sobre este tema en particular en ese documento, eso parece al menos un respaldo tácito de la práctica.Así que abogo por omitirlo; otros no están de acuerdo (¡a menudo con vehemencia!) En cualquier caso, si encuentra código que lo omite, sabrá que el estándar lo respalda explícitamente y sabrá lo que significa.
fuente
return 0;
, sin embargo, me gustaría señalar que muchos compiladores de esa época también implementaron un implícitoreturn 0;
incluso antes de que fuera estandarizado.return 0
durante más de una década. También las versiones actuales de Microsoft C también lo admiten . ¿Quizás su información está desactualizada?Lo que debe devolver depende de lo que desee hacer con el ejecutable. Por ejemplo, si está utilizando su programa con un shell de línea de comando, entonces necesita devolver 0 para un éxito y un no cero para el fracaso. Entonces podrá utilizar el programa en shells con procesamiento condicional dependiendo del resultado de su código. También puede asignar cualquier valor distinto de cero según su interpretación, por ejemplo, para errores críticos, diferentes puntos de salida del programa podrían terminar un programa con diferentes valores de salida, y que está disponible para el shell de llamada que puede decidir qué hacer al inspeccionar el valor devuelto. Si el código no está destinado a usarse con shells y el valor devuelto no molesta a nadie, entonces podría omitirse. Yo personalmente uso la firma
int main (void) { .. return 0; .. }
fuente
main
es compatible conint
. Por lo tanto, regresarint
no será un problema. Aunque se permiten otros tipos de retorno, en ese caso la variable de entorno que tiene el valor de retorno no se especificará. Pero si un programador lo hacereturn 0;
en bash, puede usarse para hacer ramas.Si realmente tiene problemas relacionados con la eficiencia de devolver un número entero de un proceso, probablemente debería evitar llamar a ese proceso tantas veces que este valor devuelto se convierta en un problema.
Si está haciendo esto (llame a un proceso tantas veces), debe encontrar una manera de poner su lógica directamente dentro de la persona que llama, o en un archivo DLL, sin asignar un proceso específico para cada llamada; Las asignaciones de procesos múltiples le brindan el problema de eficiencia relevante en este caso.
En detalle, si solo desea saber si devolver 0 es más o menos eficiente que devolver 1, podría depender del compilador en algunos casos, pero genéricamente, suponiendo que se lean desde la misma fuente (local, campo, constante, incrustado en el código, resultado de la función, etc.) requiere exactamente el mismo número de ciclos de reloj.
fuente
Aquí hay una pequeña demostración del uso de códigos de retorno ...
Al usar las diversas herramientas que proporciona el terminal de Linux, se puede usar el código de retorno, por ejemplo, para el manejo de errores después de que se haya completado el proceso. Imagine que el siguiente archivo de texto myfile está presente:
Cuando ejecuta el comando grep, se crea un proceso. Una vez que está terminado (y no se rompió), devuelve un código entre 0 y 255. Por ejemplo:
Si lo haces
obtendrás un 0. ¿Por qué? Porque grep encontró una coincidencia y devolvió un código de salida 0, que es el valor habitual para salir con éxito. Vamos a verlo de nuevo pero con algo que no está dentro de nuestro archivo de texto y, por lo tanto, no se encontrarán coincidencias:
Dado que grep no pudo hacer coincidir el token "foo" con el contenido de nuestro archivo, el código de retorno es 1 (este es el caso habitual cuando ocurre una falla, pero como se indicó anteriormente, tiene muchos valores para elegir).
Ahora el siguiente script bash (simplemente escríbalo en un terminal de Linux) aunque muy básico debería dar una idea del manejo de errores:
Después de la segunda línea, no se imprime nada en el terminal ya que "foo" hizo que grep devolviera 1 y verificamos si el código de retorno de grep era igual a 0. La segunda instrucción condicional hace eco de su mensaje en la última línea, ya que es verdadero debido a CHECK == 1.
Como puede ver si está llamando a este y a ese proceso, a veces es esencial ver lo que ha devuelto (por el valor de retorno de main ()).
fuente
if grep foo myfile; then echo 'Match found'; else echo 'No match was found'; fi
: probar el estado de devolución directamente. Si desea capturar el estado (para informes, etc.), entonces utiliza una asignación. Puede usarif grep foo myfile; CHECK=$?; [ "$CHECK" = 0 ]; then echo 'Match found'; else echo 'No match was found'; fi
o puede usar tres líneas. También puede usar las opciones-s
y-q
paragrep
evitar que aparezcan las coincidencias o los mensajes de error de rutina. Sin embargo, esto es minucias de shell, el punto clave, que el estado de salida puede ser útil, está bien.Esas palabras "(más eficiente)" no cambian la pregunta. A menos que se encuentre en un entorno independiente, hay una forma universalmente correcta de declarar
main()
, y es como regresar int.No es lo que debería
main()
regresar, es lo que símain()
regresa.main()
es, por supuesto, una función que alguien más llama. No tienes ningún control sobre el código que llamamain()
. Por lo tanto, debe declararmain()
con una firma de tipo correcto para que coincida con la persona que llama. Simplemente no tienes otra opción en el asunto. No tiene que preguntarse qué es más o menos eficiente, o qué es mejor o peor estilo, ni nada de eso, porque la respuesta ya está perfectamente bien definida, para usted, según los estándares C y C +. Solo síguelos.0 para el éxito, distinto de cero para el fracaso. De nuevo, no es algo que necesite (o que elija): está definido por la interfaz a la que se supone que se está conformando.
fuente