¿Cuáles son las firmas válidas para la función main() de C?

Resuelto Prady asked hace 14 años • 5 respuestas

¿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?

Prady avatar Jan 21 '10 16:01 Prady
Aceptado

La C11norma 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, intse puede reemplazar por un typedefnombre definido como int, o el tipo de argvse puede escribir como char ** 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 de inty sin parámetros:

int main(void) { /* ... */ }

o con dos parámetros (a los que nos referimos aquí como argcy argv, 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 mainfunción deberán obedecer las siguientes restricciones:

  • El valor de argcno será negativo.

  • argv[argc]será un puntero nulo.

  • Si el valor de argces mayor que cero, los miembros de la matriz argv[0]hasta argv[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 argces mayor que cero, la cadena a la que apunta argv[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 de argces mayor que uno, las cadenas a las que apunta argv[1]representa argv[argc-1]los parámetros del programa.

  • Los parámetros argcy argvlas cadenas a las que apunta la argvmatriz 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.1ese 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.

paxdiablo avatar Jan 21 '2010 09:01 paxdiablo

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 de inty sin parámetros:

int main(void) { /* ... */ }

o con dos parámetros (a los que nos referimos aquí como argcy argv, 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, intse puede reemplazar por un nombre typedef definido como int, o el tipo se argvpuede escribir como char **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 nulo char, 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 mainy wmainse pueden declarar como de retorno void(sin valor de retorno). Si declara maino wmainregresa 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 cuando maino wmainse declara como void, debe utilizar la exitfunció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 **envpun 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 -Werrorcon 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.

Jonathan Leffler avatar Nov 25 '2010 04:11 Jonathan Leffler

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.

unwind avatar Jan 21 '2010 09:01 unwind

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 WinMaintambién lo hay.

kennytm avatar Jan 21 '2010 10:01 kennytm
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 envpproporciona un entorno, de otro modo accesible a través degetenv()

flashnik avatar Jan 21 '2010 09:01 flashnik