variable valores una todas tipos son retorno retornan qué que publicas parametros locales llamar lenguaje las hay globales funciones funcion estaticas entre ejemplos diferencia con como c++ main language-lawyer

c++ - valores - variables locales pdf



¿Cómo puede funcionar un programa con una variable global llamada main en lugar de una función main? (7)

Considere el siguiente programa:

#include <iostream> int main = ( std::cout << "C++ is excellent!/n", 195 );

Usando g ++ 4.8.1 (mingw64) en el sistema operativo Windows 7, el programa compila y funciona bien, imprimiendo:

C ++ es excelente!

a la consola main parece ser una variable global en lugar de una función; ¿Cómo se puede ejecutar este programa sin la función main() ? ¿Este código se ajusta al estándar C ++? ¿El comportamiento del programa está bien definido? También he usado la opción -pedantic-errors pero el programa aún se compila y ejecuta.


Antes de entrar en el meollo de la pregunta sobre lo que está sucediendo, es importante señalar que el programa está mal formado según el informe de defectos 1886: Enlace de idioma para main () :

[...] Un programa que declara una variable main en el ámbito global o que declara el nombre main con enlace de lenguaje C (en cualquier espacio de nombres) está mal formado. [...]

Las versiones más recientes de clang y gcc hacen que esto sea un error y el programa no se compilará ( vea el ejemplo de gcc live ):

error: cannot declare ''::main'' to be a global variable int main = ( std::cout << "C++ is excellent!/n", 195 ); ^

Entonces, ¿por qué no había diagnóstico en versiones anteriores de gcc y clang? Este informe de defectos ni siquiera tenía una resolución propuesta hasta fines de 2014 y, por lo tanto, este caso solo fue explícitamente mal formado recientemente, lo que requiere un diagnóstico.

Antes de esto, parece que este sería un comportamiento indefinido ya que estamos violando un requisito del borrador del estándar C ++ de la sección 3.6.1 [basic.start.main] :

Un programa contendrá una función global llamada main, que es el inicio designado del programa. [...]

El comportamiento indefinido es impredecible y no requiere un diagnóstico. La inconsistencia que vemos con la reproducción del comportamiento es un comportamiento indefinido típico.

Entonces, ¿qué está haciendo realmente el código y por qué en algunos casos produce resultados? Veamos que tenemos:

declarator | initializer---------------------------------- | | | v v v int main = ( std::cout << "C++ is excellent!/n", 195 ); ^ ^ ^ | | | | | comma operator | primary expression global variable of type int

Tenemos main que es un int declarado en el espacio de nombres global y se está inicializando, la variable tiene una duración de almacenamiento estático. La implementación define si la inicialización tendrá lugar antes de que se intente llamar a main pero parece que gcc lo hace antes de llamar a main .

El código usa el operador de coma , el operando izquierdo es una expresión de valor descartado y se usa aquí únicamente para el efecto secundario de llamar a std::cout . El resultado del operador de coma es el operando correcto, que en este caso es el prvalue 195 que se asigna a la variable main .

Podemos ver que sergej señala que el ensamblaje generado muestra que se llama a cout durante la inicialización estática. Aunque el punto de discusión más interesante para ver la sesión de Godbolt en vivo sería este:

main: .zero 4

y el subsiguiente:

movl $195, main(%rip)

El escenario probable es que el programa salta al símbolo main esperando que haya un código válido y, en algunos casos, tendrá una falla seg . Entonces, si ese es el caso, esperaríamos almacenar un código de máquina válido en la variable main podría conducir a un programa viable , suponiendo que estemos ubicados en un segmento que permite la ejecución del código. Podemos ver que esta entrada de IOCCC de 1984 hace exactamente eso .

Parece que podemos obtener gcc para hacer esto en C usando ( verlo en vivo ):

const int main = 195 ;

Seg-falla si la variable main no es constante probablemente porque no se encuentra en una ubicación ejecutable, Hat Tip a este comentario aquí que me dio esta idea.

Vea también la respuesta de FUZxxl aquí a una versión C específica de esta pregunta.


Desde 3.6.1 / 1:

Un programa contendrá una función global llamada main, que es el inicio designado del programa. La implementación se define si se requiere un programa en un entorno independiente para definir una función principal.

A partir de esto, parece que g ++ permite un programa (presumiblemente como la cláusula "independiente") sin una función principal.

Luego de 3.6.1 / 3:

La función main no se utilizará (3.2) dentro de un programa. El enlace (3.5) de main está definido en la implementación. Un programa que declara que main es inline o static está mal formado. El nombre principal no está reservado de otra manera.

Así que aquí aprendemos que está perfectamente bien tener una variable entera llamada main .

Finalmente, si se pregunta por qué se imprime la salida, la inicialización de int main usa el operador de coma para ejecutar cout en init estático y luego proporciona un valor integral real para hacer la inicialización.


Ese es un programa mal formado. Se bloquea en mi entorno de prueba, cygwin64 / g ++ 4.9.3.

De la norma:

3.6.1 Función principal [basic.start.main]

1 Un programa contendrá una función global llamada main, que es el inicio designado del programa.


Estás haciendo un trabajo complicado aquí. Como principal (de alguna manera) podría declararse como entero. Usó el operador de lista para imprimir el mensaje y luego le asignó 195. Como dijo alguien a continuación, que no se consuela con C ++, es cierto. Pero como el compilador no encontró ningún nombre definido por el usuario, main, no se quejó. Recuerde que main no es una función definida por el sistema, su función definida por el usuario y la cosa desde la cual el programa comienza a ejecutarse es Main Module, no main (), específicamente. Nuevamente, main () es llamado por la función de inicio que es ejecutada por el cargador intencionalmente. Luego, todas sus variables se inicializan, y mientras se inicializa, se genera así. Eso es. El programa sin main () está bien, pero no es estándar.


He intentado esto en un sistema operativo Win7 de 64 bits con VS2013 y se compila correctamente, pero cuando intento compilar la aplicación, recibo este mensaje desde la ventana de salida.

1>------ Build started: Project: tempTest, Configuration: Debug Win32 ------ 1>LINK : fatal error LNK1561: entry point must be defined ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========


La razón por la que creo que esto funciona es que el compilador no sabe que está compilando la función main() , por lo que compila un entero global con efectos secundarios de asignación.

El formato de objeto en el que se compila esta unidad de traducción no es capaz de diferenciar entre un símbolo de función y un símbolo de variable .

Entonces el enlazador felizmente se vincula al símbolo principal (variable) y lo trata como una llamada a la función. Pero no hasta que el sistema de tiempo de ejecución haya ejecutado el código de inicialización de la variable global.

Cuando ejecuté la muestra, se imprimió pero luego causó una falla seg . Supongo que es cuando el sistema de tiempo de ejecución intentó ejecutar una variable int como si fuera una función .


gcc 4.8.1 genera el siguiente ensamblado x86:

.LC0: .string "C++ is excellent!/n" subq $8, %rsp #, movl std::__ioinit, %edi #, call std::ios_base::Init::Init() # movl $__dso_handle, %edx #, movl std::__ioinit, %esi #, movl std::ios_base::Init::~Init(), %edi #, call __cxa_atexit # movl $.LC0, %esi #, movl std::cout, %edi #, call std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) # movl $195, main(%rip) #, main addq $8, %rsp #, ret main: .zero 4

Tenga en cuenta que cout se llama durante la inicialización, ¡no en la función main !

.zero 4 declara 4 bytes (inicializados en 0) comenzando en la ubicación main , donde main es el nombre de la variable [!] .

El símbolo main se interpreta como el inicio del programa. El comportamiento depende de la plataforma.