Sé que hay dos firmas diferentes para escribir el método principal:
int main()
{
//Code
}
o para manejar el argumento de la línea de comando, lo escribimos como-
int main(int argc, char * argv[])
{
//code
}
En C++
Sé que podemos sobrecargar un método, sino en C
cómo manejar el compilador de estas dos firmas diferentes de main
la función?
main
método en un solo programa enC
(o, en realidad, en casi cualquier lenguaje con tal construcción).main
, recomiendo el libro clásico de John R. Levines "Linkers & Loaders".int main(void)
noint main()
(aunque nunca he visto un compilador que rechace laint main()
forma).()
formulario es obsoleto y no está claro si siquiera está permitidomain
(a menos que la implementación lo documente específicamente como un formulario permitido). El estándar C (consulte 5.1.2.2.1 Inicio del programa) no menciona el()
formulario, que no es del todo equivalente al()
formulario. Los detalles son demasiado largos para este comentario.Respuestas:
Algunas de las características del lenguaje C comenzaron como hacks que simplemente funcionaron.
Varias firmas para listas de argumentos principales y de longitud variable es una de esas características.
Los programadores notaron que pueden pasar argumentos adicionales a una función y no pasa nada malo con su compilador dado.
Este es el caso si las convenciones de llamada son tales que:
Un conjunto de convenciones de llamadas que obedecen estas reglas es el paso de parámetros basados en la pila, mediante el cual el llamador muestra los argumentos y se empujan de derecha a izquierda:
En los compiladores en los que se da este tipo de convención de llamada, no es necesario hacer nada especial para admitir los dos tipos
main
o incluso los tipos adicionales.main
puede ser una función sin argumentos, en cuyo caso es ajeno a los elementos que se insertaron en la pila. Si es una función de dos argumentos, entonces buscaargc
yargv
como los dos elementos de la pila más altos. Si es una variante de tres argumentos específica de la plataforma con un puntero de entorno (una extensión común), eso también funcionará: encontrará ese tercer argumento como el tercer elemento de la parte superior de la pila.Por tanto, una llamada fija funciona para todos los casos, lo que permite vincular al programa un único módulo fijo de puesta en marcha. Ese módulo podría escribirse en C, como una función parecida a esta:
En otras palabras, este módulo de inicio solo llama a un main de tres argumentos, siempre. Si main no toma argumentos, o solo
int, char **
, resulta que funciona bien, así como si no toma argumentos, debido a las convenciones de llamada.Si tuviera que hacer este tipo de cosas en su programa, ISO C no sería portátil y lo consideraría un comportamiento indefinido: declarar y llamar a una función de una manera y definirla de otra. Pero el truco de inicio de un compilador no tiene por qué ser portátil; no se rige por las reglas de los programas portátiles.
Pero suponga que las convenciones de llamada son tales que no puede funcionar de esta manera. En ese caso, el compilador debe tratar
main
especialmente. Cuando se da cuenta de que está compilando lamain
función, puede generar código que sea compatible con, digamos, una llamada de tres argumentos.Es decir, escribe esto:
Pero cuando el compilador lo ve, esencialmente realiza una transformación de código para que la función que compila se parezca más a esto:
excepto que los nombres
__argc_ignore
no existen literalmente. No se introducen tales nombres en su ámbito y no habrá ninguna advertencia sobre los argumentos no utilizados. La transformación de código hace que el compilador emita código con el enlace correcto que sabe que tiene que limpiar tres argumentos.Otra estrategia de implementación es que el compilador o quizás el enlazador genere la
__start
función de manera personalizada (o como se llame), o al menos seleccione una de varias alternativas precompiladas. La información podría almacenarse en el archivo de objeto sobre cuál de las formas admitidas demain
se está utilizando. El vinculador puede ver esta información y seleccionar la versión correcta del módulo de inicio que contiene una llamada a lamain
que es compatible con la definición del programa. Las implementaciones de C generalmente tienen solo una pequeña cantidad de formas compatibles, pormain
lo que este enfoque es factible.Los compiladores para el lenguaje C99 siempre tienen que tratar
main
especialmente, hasta cierto punto, para soportar el truco que si la función termina sin unareturn
declaración, el comportamiento es como sireturn 0
se hubiera ejecutado. Esto, nuevamente, puede tratarse mediante una transformación de código. El compilador nota quemain
se está compilando una función llamada . Luego comprueba si el final del cuerpo es potencialmente alcanzable. Si es así, inserta unreturn 0;
fuente
NO hay sobrecarga
main
incluso en C ++. La función principal es el punto de entrada para un programa y solo debe existir una única definición.Para el estándar C
Para C ++ estándar:
El estándar C ++ dice explícitamente "[la función principal] tendrá un tipo de retorno de tipo int, pero de lo contrario su tipo está definido por la implementación", y requiere las mismas dos firmas que el estándar C.
En un entorno alojado ( entorno AC que también admite las bibliotecas C): el sistema operativo llama
main
.En un entorno no alojado (uno destinado a aplicaciones integradas) siempre puede cambiar el punto de entrada (o salida) de su programa utilizando las directivas del preprocesador como
Donde prioridad es un número integral opcional.
El inicio de Pragma ejecuta la función antes de la función principal (prioridad) y la salida de pragma ejecuta la función después de la función principal. Si hay más de una directiva de inicio, la prioridad decide cuál se ejecutará primero.
fuente
No hay necesidad de sobrecargar. Sí, hay 2 versiones, pero solo se puede usar una a la vez.
fuente
Esta es una de las extrañas asimetrías y reglas especiales del lenguaje C y C ++.
En mi opinión, existe solo por razones históricas y no hay una lógica seria real detrás de él. Tenga en cuenta que
main
también es especial por otras razones (por ejemplo,main
en C ++ no puede ser recursivo y no puede tomar su dirección y en C99 / C ++ se le permite omitir unareturn
declaración final ).Tenga en cuenta también que incluso en C ++ no es una sobrecarga ... o un programa tiene la primera forma o tiene la segunda forma; no puede tener ambos.
fuente
return
declaración en C (desde C99).main()
y tomar su dirección; C ++ aplica límites que C no aplica.argc
cuando se repite (5.1.2.2.1 no especifica limitaciones enargc
yargv
aplicar solo a la llamada inicial amain
).Lo que es inusual
main
no es que se pueda definir de más de una manera, es que solo se puede definir de dos maneras diferentes.main
es una función definida por el usuario; la implementación no declara un prototipo para él.Lo mismo es cierto para
foo
obar
, pero puede definir funciones con esos nombres de la forma que desee.La diferencia es que
main
es invocada por la implementación (el entorno de ejecución), no solo por su propio código. La implementación no se limita a la semántica ordinaria de llamadas a funciones de C, por lo que puede (y debe) lidiar con algunas variaciones, pero no es necesario que maneje infinitas posibilidades. Elint main(int argc, char *argv[])
formulario permite argumentos de línea de comandos, yint main(void)
en C oint main()
en C ++ es solo una conveniencia para programas simples que no necesitan procesar argumentos de línea de comandos.En cuanto a cómo el compilador maneja esto, depende de la implementación. La mayoría de los sistemas probablemente tienen convenciones de llamada que hacen que las dos formas sean efectivamente compatibles, y cualquier argumento que se pase a un
main
definido sin parámetros se ignora en silencio. Si no, no sería difícil para un compilador o enlazador tratarlo de maneramain
especial. Si tiene curiosidad por saber cómo funciona en su sistema , puede consultar algunas listas de ensamblaje.Y como muchas cosas en C y C ++, los detalles son en gran parte el resultado de la historia y las decisiones arbitrarias tomadas por los diseñadores de los lenguajes y sus predecesores.
Tenga en cuenta que tanto C como C ++ permiten otras definiciones definidas por la implementación para
main
, pero rara vez hay una buena razón para usarlas. Y para las implementaciones independientes (como los sistemas integrados sin SO), el punto de entrada del programa está definido por la implementación y ni siquiera se llama necesariamentemain
.fuente
El
main
es solo un nombre para una dirección de inicio decidida por el vinculador, dondemain
es el nombre predeterminado. Todos los nombres de funciones en un programa son direcciones de inicio donde comienza la función.Los argumentos de la función se insertan / aparecen en / desde la pila, por lo que si no hay argumentos especificados para la función, no hay argumentos presionados / activados / desactivados en la pila. Así es como main puede funcionar tanto con argumentos como sin ellos.
fuente
donde la variable argc almacena el recuento de datos que se pasan y argv es una matriz de punteros a char que apunta a los valores pasados desde la consola. De lo contrario, siempre es bueno ir con
Sin embargo, en cualquier caso, puede haber uno y solo un main () en un programa, ya que ese es el único punto en el que desde un programa comienza su ejecución y, por lo tanto, no puede haber más de uno. (espero que sea digno)
fuente
Se hizo una pregunta similar antes: ¿Por qué se compila una función sin parámetros (en comparación con la definición de función real)?
Una de las respuestas mejor clasificadas fue:
Entonces, supongo que es cómo
main
se declara (si puede aplicar el término "declarado" amain
). De hecho, puedes escribir algo como esto:y aún se compilará y ejecutará.
fuente
main
, ya que hay un problema que aún no se menciona: ¡aún más argumentos a favormain
! "Unix (pero no Posix.1) y Microsoft Windows" agreganchar **envp
(recuerdo que DOS también lo permitió, ¿no?), Y Mac OS X y Darwin agregan otro puntero char * de "información arbitraria proporcionada por el sistema operativo". wikipediaNo es necesario que anule esto, ya que solo se usará una a la vez. Sí, hay 2 versiones diferentes de la función principal.
fuente