¿Cuál es la declaración adecuada de main?

147

¿Cuál es la firma adecuada de la mainfunción en C ++? ¿Cuál es el tipo de retorno correcto y qué significa devolver un valor main? ¿Cuáles son los tipos de parámetros permitidos y cuáles son sus significados?

¿Es esto específico del sistema? ¿Han cambiado esas reglas con el tiempo? ¿Qué pasa si los violo?

flujo libre
fuente
1
Esto está muy relacionado o es un duplicado de lo que debería mainregresar en C y C ++ .
Jonathan Leffler
@ JonathanLeffler No es broma ... se agregó a la lista de duplicados en la revisión 6 hace aproximadamente 8 meses.
fredoverflow

Respuestas:

192

La mainfunción debe declararse como una función no miembro en el espacio de nombres global. Esto significa que no puede ser una función miembro estática o no estática de una clase, ni puede colocarse en un espacio de nombres (incluso el espacio de nombres sin nombre).

El nombre mainno está reservado en C ++, excepto como una función en el espacio de nombres global. Usted es libre de declarar otras entidades nombradas main, incluidas, entre otras cosas, clases, variables, enumeraciones, funciones miembro y funciones no miembros que no están en el espacio de nombres global.

Puede declarar una función nombrada maincomo una función miembro o en un espacio de nombres, pero dicha función no sería la mainfunción que designa el inicio del programa.

La mainfunción no se puede declarar como statico inline. Tampoco se puede sobrecargar; solo puede haber una función nombrada mainen el espacio de nombres global.

los main función no se puede usar en su programa: no se le permite llamar a la mainfunción desde ninguna parte de su código, ni se le permite tomar su dirección.

El tipo de retorno de maindebe serint . No se permite ningún otro tipo de retorno (esta regla está en negrita porque es muy común ver programas incorrectos que declaran maincon un tipo de retorno devoid ; esta es probablemente la regla más frecuentemente violada con respecto a la mainfunción).

Hay dos declaraciones mainque deben permitirse:

int main()               // (1)
int main(int, char*[])   // (2)

En (1) , no hay parámetros.

En (2) , hay dos parámetros y se denominan convencionalmente argcy argv, respectivamente. argves un puntero a una matriz de cadenas C que representan los argumentos del programa. argces el número de argumentos en la argvmatriz.

Por lo general, argv[0]contiene el nombre del programa, pero este no es siempre el caso. argv[argc]se garantiza que es un puntero nulo.

Tenga en cuenta que dado que un argumento de tipo matriz (como char*[]) es realmente solo un argumento de tipo puntero disfrazado, las dos siguientes son formas válidas de escribir (2) y ambas significan exactamente lo mismo:

int main(int argc, char* argv[])
int main(int argc, char** argv)

Algunas implementaciones pueden permitir otros tipos y números de parámetros; tendría que consultar la documentación de su implementación para ver qué admite.

main()se espera que devuelva cero para indicar éxito y no cero para indicar falla. No es necesario que escriba explícitamente una returndeclaración en main(): si deja main()regresar sin una returndeclaración explícita , es lo mismo que si hubiera escrito return 0;. Las siguientes dos main()funciones tienen el mismo comportamiento:

int main() { }
int main() { return 0; }

Hay dos macros, EXIT_SUCCESSy EXIT_FAILURE, definidas en <cstdlib>eso, también se pueden devolver main()para indicar el éxito y el fracaso, respectivamente.

El valor devuelto por main()se pasa a la exit()función, que finaliza el programa.

Tenga en cuenta que todo esto se aplica solo cuando se compila para un entorno alojado (informalmente, un entorno donde tiene una biblioteca estándar completa y hay un sistema operativo que ejecuta su programa). También es posible compilar un programa C ++ para un entorno independiente (por ejemplo, algunos tipos de sistemas integrados), en cuyo caso el inicio y la terminación están totalmente definidos por la implementación y main()es posible que ni siquiera se requiera una función. Sin embargo, si está escribiendo C ++ para un SO de escritorio moderno, está compilando para un entorno alojado.

James McNellis
fuente
1
IIRC los únicos valores de retorno garantizados son 0, EXIT_SUCCESS (mismo efecto que 0) y EXIT_FAILURE. EDITAR: Ah, está bien, se pueden devolver otros valores de estado distintos de cero, pero con un significado definido por la implementación. Solo se garantiza que EXIT_FAILURE se interpretará de alguna manera como un valor de falla.
Derrick Turk
44
@Synetech: La pregunta se formula en su primera oración, "¿Cuál es la firma adecuada de la función principal en C ++?" y la pregunta está etiquetada tanto [c ++] como [c ++ - faq]. No puedo evitarlo si los usuarios de Java o C # (o cualquier otra persona) todavía están confundidos. C # requiere Mainser una función miembro estática porque ni siquiera tiene funciones que no sean miembros. Incluso C89 requiere mainvolver int. No estoy suficientemente familiarizado con K&R C para conocer sus reglas exactas, pero supongo que también requiere mainregresar intya que mainsin tipo de retorno era algo común y no type = implícito inten K&R.
James McNellis
3
@Suhail: Porque el estándar de idioma dice que el tipo de retorno será int.
James McNellis
1
@Suhail: Sí. Su código no será correcto en C ++ y muchos compiladores rechazarán su código.
James McNellis
2
@Suhail: Visual C ++ permite un voidtipo de retorno como una extensión de lenguaje . Los compiladores que no lo permiten incluyen GCC y Comeau.
James McNellis
15

De los documentos estándar, 3.6.1.2 Función principal ,

Tendrá un tipo de retorno de tipo int, pero de lo contrario su tipo está definido por la implementación. Todas las implementaciones permitirán las dos definiciones siguientes de main:

int main() { / ... / } y int main(int argc, char* argv[]) { / ... / }

En la última forma se argcindicará el número de argumentos pasados ​​al programa desde el entorno en el que se ejecuta el programa. Si argc no es cero, estos argumentos se proporcionarán en argv [0] a través de argv [argc-1] como punteros a la inicial caracteres de cadenas multibyte terminadas en nulo .....

Espero que ayude..

liaK
fuente
2
¿Hay alguna razón específica de por qué el tipo de retorno maindebería ser int?
Suhail Gupta
1
@SuhailGupta: para que el proceso de llamada sepa si este proceso debe considerarse exitoso o no. Permitir voidrompe ese modelo. Ni siquiera tiene sentido si tuvieras que significa "siempre considerar el éxito". Debido a que no tenía forma de decir si el proceso realmente falló, ¿ realmente tuvo éxito? No, vuelve int.
Carreras de ligereza en órbita el
4

La redacción exacta del último estándar publicado (C ++ 14) es:

Una implementación permitirá ambos

  • una función de ()regresar inty

  • una función de (int, puntero a puntero para char)volverint

como el tipo de main.

Esto deja en claro que la ortografía alternativa está permitida siempre que el tipo de mainsea ​​el tipo int()o int(int, char**). Entonces lo siguiente también está permitido:

  • int main(void)
  • auto main() -> int
  • int main ( )
  • signed int main()
  • typedef char **a; typedef int b, e; e main(b d, a c)
MM
fuente
1
NÓTESE BIEN. Publiqué esta respuesta como en comentarios en otro hilo, alguien intentó citar este hilo como evidencia de que int main(void)no era correcto en C ++.
MM
3
@Stargateur auto main() -> intno tiene un tipo de devolución deducido. Preste atención a {in "(auto main () {... no está permitido)" y aprenda a saber cuándo aún no sabe lo suficiente como para agregar algo significativo.
3

Los dos platos principales válidos son int main()y int main(int, char*[]). Cualquier otra cosa puede o no compilarse. Si mainno devuelve un valor explícitamente, 0 se devuelve implícitamente.

metal de piedra
fuente
1
Nunca he visto que el código no se compila cuando menciono el tipo de retorno de mainser anulado. ¿Hay alguna razón específica por la que el tipo de retorno de main debería ser int?
Suhail Gupta
44
La especificación del lenguaje dice que main debe tener un tipo de retorno de int. Cualquier otro tipo de retorno permitido por su compilador es una mejora específica del compilador. Básicamente, usar void significa que está programando en un lenguaje similar pero no C ++.
stonemetal
2
La razón por la cual el estándar requiere un inttipo de retorno maines que este valor se entrega al shell como el código de salida del programa y shespera un int.
uckelman
Tal vez la razón es la disciplina? Puede haber más de un camino de salida. Si el tipo de retorno es void, todos están en silencio. Con inttenemos que definir el valor de salida específico para cada retorno de main.
Andreas Spindler
2

Detalles sobre los valores de retorno y su significado

Por 3.6.1 ( [basic.start.main]):

Una declaración return maintiene el efecto de abandonar la mainfunción (destruir cualquier objeto con duración de almacenamiento automática) y llamar std::exitcon el valor devuelto como argumento. Si el control llega al final de mainsin encontrar una returndeclaración, el efecto es el de ejecutar

return 0;

El comportamiento de std::exitse detalla en la sección 18.5 ( [support.start.term]) y describe el código de estado:

Finalmente, el control se devuelve al entorno del host. Si el estado es cero o EXIT_SUCCESS, se devuelve una forma definida por la implementación del estado de terminación exitosa. Si el estado es EXIT_FAILURE, se devuelve una forma definida por la implementación de la terminación fallida del estado. De lo contrario, el estado devuelto está definido por la implementación.

Ben Voigt
fuente