¿Cuáles son las firmas válidas para la función main() de C?
¿Cuáles son realmente las firmas válidas para la función principal en C? Lo sé:
int main(int argc, char *argv[])
¿Hay otros válidos?
La C11
norma menciona explícitamente estos dos:
int main(void);
int main(int argc, char* argv[]);
aunque sí menciona la frase “o equivalente” con la siguiente nota a pie de página:
Por lo tanto,
int
se puede reemplazar por untypedef
nombre definido comoint
, o el tipo deargv
se puede escribir comochar ** argv
, y así sucesivamente.
Además, también ofrece más posibilidades (definidas por la implementación).
El texto relevante (sección 5.1.2.2.1
, pero este aspecto particular no ha cambiado desde C99
) establece:
La función llamada al inicio del programa se llama
main
. La implementación no declara ningún prototipo para esta función. Se definirá con un tipo de retorno deint
y sin parámetros:
int main(void) { /* ... */ }
o con dos parámetros (a los que nos referimos aquí como
argc
yargv
, aunque se puede utilizar cualquier nombre, ya que son locales de la función en la que se declaran):
int main(int argc, char *argv[]) { /* ... */ }
o equivalente; o de alguna otra manera definida por la implementación.
Si se declaran, los parámetros de la
main
función deberán obedecer las siguientes restricciones:
El valor de
argc
no será negativo.
argv[argc]
será un puntero nulo.Si el valor de
argc
es mayor que cero, los miembros de la matrizargv[0]
hastaargv[argc-1]
inclusive contendrán punteros a cadenas, a las que el entorno host les dará valores definidos por la implementación antes del inicio del programa. La intención es proporcionar al programa información determinada antes del inicio del programa desde cualquier otro lugar del entorno alojado. Si el entorno anfitrión no es capaz de suministrar cadenas con letras tanto en mayúsculas como en minúsculas, la implementación deberá garantizar que las cadenas se reciban en minúsculas.Si el valor de
argc
es mayor que cero, la cadena a la que apuntaargv[0]
representa el nombre del programa;argv[0][0]
será el carácter nulo si el nombre del programa no está disponible en el entorno host. Si el valor deargc
es mayor que uno, las cadenas a las que apuntaargv[1]
representaargv[argc-1]
los parámetros del programa.Los parámetros
argc
yargv
las cadenas a las que apunta laargv
matriz serán modificables por el programa y conservarán sus últimos valores almacenados entre el inicio y la finalización del programa.
Tenga en cuenta que esto es para un entorno alojado, los que normalmente ve en los programas C. Un entorno independiente (como un sistema integrado) está mucho menos restringido, como se indica en 5.1.2.1
ese mismo estándar:
En un entorno independiente (en el que la ejecución del programa C puede tener lugar sin ningún beneficio de un sistema operativo), el nombre y el tipo de la función llamada al inicio del programa están definidos por la implementación. Cualquier instalación de biblioteca disponible para un programa independiente, aparte del conjunto mínimo requerido por la cláusula 4, está definida por la implementación.
Estándar C
Para un entorno alojado (que es el normal), el estándar C99 dice:
5.1.2.2.1 Inicio del programa
La función llamada al inicio del programa se llama
main
. La implementación no declara ningún prototipo para esta función. Se definirá con un tipo de retorno deint
y sin parámetros:
int main(void) { /* ... */ }
o con dos parámetros (a los que nos referimos aquí como
argc
yargv
, aunque se puede utilizar cualquier nombre, ya que son locales de la función en la que se declaran):
int main(int argc, char *argv[]) { /* ... */ }
o equivalente; 9) o de alguna otra manera definida por la implementación.
9) Por lo tanto,
int
se puede reemplazar por un nombre typedef definido comoint
, o el tipo seargv
puede escribir comochar **argv
, y así sucesivamente.
Los estándares C11 y C18 dicen esencialmente lo mismo que el estándar C99.
C++ estándar
El estándar C++98 dice:
3.6.1 Función principal [basic.start.main]
1 Un programa contendrá una función global llamada principal, que es el inicio designado del programa. [...]
2 Una implementación no deberá predefinir la función principal. Esta función no deberá sobrecargarse. Tendrá un tipo de retorno de tipo int, pero por lo demás su tipo está definido por la implementación. Todas las implementaciones permitirán las dos definiciones siguientes de principal:
int main() { /* ... */ }
y
int main(int argc, char* argv[]) { /* ... */ }
El estándar C++ dice explícitamente "[la función principal] tendrá un tipo de retorno de tipo int
, pero por lo demás su tipo está definido por la implementación" y requiere las mismas dos firmas que el estándar C. Por lo tanto, el estándar C++ no permite directamente un 'void main()', aunque no hay nada que pueda hacer para evitar que una implementación que no se ajuste al estándar permita alternativas (ni que una implementación que se ajuste al estándar permita alternativas como extensiones del estándar).
Los estándares C++03, C++11, C++14 y C++17 dicen esencialmente lo mismo que C++98.
Extensión común
Clásicamente, los sistemas Unix soportan una tercera variante:
int main(int argc, char **argv, char **envp) { ... }
El tercer argumento es una lista terminada en nulo de punteros a cadenas, cada una de las cuales es una variable de entorno que tiene un nombre, un signo igual y un valor (posiblemente vacío). Si no utiliza esto, aún puede acceder al entorno a través de ' extern char **environ;
'. Esta variable (todavía) no está declarada en ningún encabezado POSIX (a pesar de las versiones anteriores de esta respuesta).
Esto está reconocido por el estándar C como una extensión común, documentada en el Anexo J:
###J.5.1 Argumentos ambientales
¶1 En un entorno alojado, la función principal recibe un tercer argumento,
char *envp[]
que apunta a una matriz de punteros terminados en nulochar
, cada uno de los cuales apunta a una cadena que proporciona información sobre el entorno para esta ejecución del programa (5.1. 2.2.1).
microsoft c
El compilador Microsoft VS 2010 es interesante. El sitio web dice:
La sintaxis de declaración para main es
int main();
o, opcionalmente,
int main(int argc, char *argv[], char *envp[]);
Alternativamente, las funciones
main
ywmain
se pueden declarar como de retornovoid
(sin valor de retorno). Si declaramain
owmain
regresa como nulo, no puede devolver un código de salida al proceso principal o al sistema operativo mediante una declaración de devolución. Para devolver un código de salida cuandomain
owmain
se declara comovoid
, debe utilizar laexit
función.
No me queda claro qué sucede (qué código de salida se devuelve al padre o al sistema operativo) cuando un programa sale void main()
, y el sitio web de MS también guarda silencio.
Curiosamente, MS no prescribe la versión de dos argumentos que main()
requieren los estándares C y C++. Solo prescribe una forma de tres argumentos donde el tercer argumento es char **envp
un puntero a una lista de variables de entorno.
La página de Microsoft también enumera otras alternativas, wmain()
que requieren cadenas de caracteres anchas y algunas más.
La versión Microsoft VS 2005 de esta página no aparece void main()
como alternativa. Las versiones desde Microsoft VS 2008 en adelante sí lo hacen.
Es int main()
lo mismo que int main(void)
?
Para obtener un análisis detallado, consulte el final de mi respuesta a Qué debería main()
devolverse en C y C++ . (Parece que una vez consideré que esta pregunta se refería a C++, aunque no es así y nunca lo hizo. En C++, no hay diferencia entre int main()
y int main(void)
y int main()
es C++ idiomático).
En C, hay una diferencia entre las dos notaciones, pero sólo se nota en casos esotéricos. Específicamente, hay una diferencia si llama a la main()
función desde su propio código, lo cual puede hacer en C y no en C++.
La int main()
notación no proporciona un prototipo para main()
, pero eso sólo importa si lo llamas recursivamente. Con int main()
, podrías escribir más adelante (en la misma función o en otra función) int rc = main("absolute", "twaddle", 2):
y formalmente el compilador no debería quejarse hasta el punto de negarse a compilar el código, aunque podría quejarse legítimamente (advertirte) al respecto (y usar -Werror
con GCC convertiría la advertencia en un error). Si usa int main(void)
, la llamada posterior a main()
debería generar un error: dijo que la función no acepta argumentos pero intentó proporcionar tres. Por supuesto, no puedes llamar legítimamente main()
antes de haberlo declarado o definido (a menos que todavía estés usando la semántica C90) y la implementación no declara un prototipo para main()
. NB: El estándar C11 ilustra ambos int main()
y int main(void)
en diferentes ejemplos; ambos son válidos en C, aunque existe una sutil diferencia entre ellos.
POSIX admite execve()
, que a su vez admite
int main(int argc, char *argv[], char *envp[])
El argumento agregado es el entorno, es decir, una matriz de cadenas con el formato NOMBRE=VALOR.
http://en.wikipedia.org/wiki/Main_function_(programming)#C_and_C.2B.2B
Además del habitual int main(int argc, char *argv[])
y el POSIX int main(int argc, char **argv, char **envp)
, en Mac OS X también es compatible
int main(int argc, char* argv[], char* envp[], char* apple[]);
Por supuesto, es sólo para Mac.
En Windows hay
int wmain(int argc, wchar_t* argv[], wchar_t* envp[]);
como la variante Unicode (en realidad, de caracteres anchos). Por supuesto que WinMain
también lo hay.
int main(void)
En algunos sistemas operativos (por ejemplo, Windows) también es válido lo siguiente:
int main(int argc, char **argv, char **envp)
donde envp
proporciona un entorno, de otro modo accesible a través degetenv()