¿Main() es realmente el inicio de un programa C++?

10 minutos de lectura

¿Main es realmente el inicio de un programa C
Nawaz

La sección $3.6.1/1 del estándar C++ dice:

Un programa debe contener una función global llamada principalque es el designado comienzo Del programa.

Ahora considere este código,

int square(int i) { return i*i; }
int user_main()
{ 
    for ( int i = 0 ; i < 10 ; ++i )
           std::cout << square(i) << endl;
    return 0;
}
int main_ret= user_main();
int main() 
{
        return main_ret;
}

Este código de ejemplo hace lo que pretendo que haga, es decir, imprimir el cuadrado de los números enteros del 0 al 9, antes de entrando en el main() función que se supone que es el “inicio” del programa.

También lo compilé con -pedantic opción, GCC 4.5.0. ¡No da ningún error, ni siquiera una advertencia!

Entonces mi pregunta es,

¿Es este código realmente conforme con el estándar?

Si cumple con el estándar, ¿no invalida lo que dice el estándar? main() no es el comienzo de este programa! user_main() ejecutado antes de la main().

Entiendo que para inicializar la variable global main_retlos use_main() ejecuta primero, pero eso es algo completamente diferente; el punto es que, es lo hace invalidar la declaración citada $3.6.1/1 de la Norma, como main() No es el comienzo Del programa; es de hecho el final de esta ¡programa!


EDITAR:

¿Cómo defines la palabra ‘comienzo’?

Se reduce a la definición de la frase. “inicio del programa”. Entonces, ¿cómo lo defines exactamente?

¿Main es realmente el inicio de un programa C
adam davis

Estás leyendo la oración incorrectamente.

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

El estándar DEFINE la palabra “comienzo” para los fines del resto del estándar. No dice que ningún código se ejecuta antes main se llama. Dice que se considera que el inicio del programa está en la función main.

Su programa es compatible. Su programa no ha “comenzado” hasta que se inicia main. La función se llama antes de que su programa “comience” de acuerdo con la definición de “inicio” en el estándar, pero eso apenas importa. MUCHO código se ejecuta antes main es siempre llamado en cada programa, no solo en este ejemplo.

A los efectos de la discusión, su función se ejecuta antes del ‘inicio’ del programa, y ​​eso cumple totalmente con el estándar.

  • Lo siento, pero no estoy de acuerdo con tu interpretación de esa cláusula.

    – Carreras de ligereza en órbita

    2 de junio de 2011 a las 9:53

  • Creo que Adam Davis tiene razón, “main” es más como algún tipo de restricción de codificación.

    – laike9m

    10 de julio de 2013 a las 6:47

  • @LightnessRacesinOrbit Nunca hice un seguimiento, pero para mí esa oración se puede resumir lógicamente en “una función global llamada main es la inicio designado Del programa” (énfasis añadido). ¿Cuál es tu interpretación de esa oración?

    – Adán Davis

    14 dic 2016 a las 21:42

  • @AdamDavis: No recuerdo cuál era mi preocupación. No puedo pensar en uno ahora.

    – Carreras de ligereza en órbita

    15 de diciembre de 2016 a las 21:37

  • @AdamDavis int user_main() es una función que se llama para inicializar int main_ret no es un factor que sería llamado para inicializar una clase (definida por el usuario). Pero eso todavía está bien. No solo los factores se ejecutan antes de main, varios códigos de inicialización pueden ejecutarse antes de main como se describe es.cppreference.com/w/cpp/language/initialization bajo inicialización dinámica no local 3) ordenada dentro de una unidad de traducción.

    – Don Slowik

    4 de marzo a las 21:07

No, C++ hace muchas cosas para “establecer el entorno” antes de la llamada de main; sin embargo, main es el inicio oficial de la parte “especificada por el usuario” del programa C++.

Parte de la configuración del entorno no es controlable (como el código inicial para configurar std::cout; sin embargo, parte del entorno es controlable como bloques globales estáticos (para inicializar variables globales estáticas). Tenga en cuenta que dado que no tiene control antes de main, no tiene control total sobre el orden en que se inicializan los bloques estáticos.

Después de main, su código está conceptualmente “totalmente en control” del programa, en el sentido de que puede especificar las instrucciones que se ejecutarán y el orden en que se ejecutarán. Multi-threading puede reorganizar el orden de ejecución del código; pero aún tiene el control con C++ porque especificó que las secciones del código se ejecutaran (posiblemente) fuera de orden.

  • +1 por esto “Tenga en cuenta que, dado que no tiene control total antes de main, no tiene control total sobre el orden en que se inicializan los bloques estáticos. Después de main, su código tiene conceptualmente “control total” del programa, en el sentido de que puede especificar las instrucciones que se deben realizar y el orden en que se deben realizar”. Esto también me hace marcar esta respuesta como respuesta aceptada… Creo que estos son puntos muy importantes, que justifican suficientemente main() como “inicio del programa”

    – Nawaz

    25 de enero de 2011 a las 22:02


  • @Nawaz: tenga en cuenta que además de no tener control total sobre el orden de inicialización, no tiene control sobre los errores de inicialización: no puede detectar excepciones en un ámbito global.

    – André Carón

    12 de marzo de 2011 a las 20:24

  • @Nawaz: ¿Qué son los bloques globales estáticos? ¿Podría explicarlo usando un ejemplo simple? Gracias

    – Destructor

    4 de mayo de 2015 a las 11:13

  • @meet: Los objetos declarados a nivel de espacio de nombres tienen static duración del almacenamiento, y como tal, estos objetos que pertenecen a diferentes unidades de traducción se pueden inicializar en ninguna orden (porque el orden es no especificado por la norma). No estoy seguro de si eso responde a su pregunta, aunque eso es lo que podría decir en el contexto de este tema.

    – Nawaz

    4 mayo 2015 a las 11:22


Su programa no se vinculará y, por lo tanto, no se ejecutará a menos que haya un archivo principal. Sin embargo, main() no provoca el inicio de la ejecución del programa porque los objetos a nivel de archivo tienen constructores que se ejecutan de antemano y sería posible escribir un programa completo que se ejecute durante su vida útil antes de que se alcance main() y dejar que main tenga un cuerpo vacío

En realidad, para hacer cumplir esto, debe tener un objeto construido antes de main y su constructor para invocar todo el flujo del programa.

Mira este:

class Foo
{
public:
   Foo();

 // other stuff
};

Foo foo;

int main()
{
}

El flujo de su programa se derivaría efectivamente de Foo::Foo()

  • +1. Pero tenga en cuenta que si tiene varios objetos globales en diferentes unidades de traducción, esto le causará problemas rápidamente, ya que el orden en que se llama a los constructores no está definido. Puede salirse con la suya con singletons e inicialización diferida, pero en un entorno de subprocesos múltiples, las cosas se ponen muy feas rápidamente. En una palabra, no hagas esto en código real.

    – Alejandro C.

    24 de enero de 2011 a las 15:07

  • Si bien probablemente debería darle a main() un cuerpo adecuado en su código y permitirle ejecutar la ejecución, el concepto de objetos fuera de ese inicio es en lo que se basan muchas bibliotecas LD_PRELOAD.

    – CashCow

    24 de enero de 2011 a las 15:11

  • @Alex: el estándar dice indefinido, pero como cuestión práctica, el orden de enlace (generalmente, según el compilador) controla el orden de inicio.

    – Thomas McLeod

    24 de enero de 2011 a las 18:48

  • @Thomas: Seguramente no intentaría ni remotamente confiar en eso. Seguramente tampoco intentaría controlar manualmente el sistema de compilación.

    – Alejandro C.

    24 de enero de 2011 a las 18:50

  • @Alex: ya no es tan importante, pero en el pasado usábamos el orden de enlace para controlar la imagen de compilación a fin de disminuir la paginación de la memoria física. Hay otras razones secundarias por las que es posible que desee controlar el orden de inicio incluso cuando no afecta la semántica del programa, como las pruebas de comparación de rendimiento de inicio.

    – Thomas McLeod

    24 de enero de 2011 a las 19:21

1646959332 341 ¿Main es realmente el inicio de un programa C
Remo.D

También etiquetó la pregunta como “C”, luego, hablando estrictamente de C, su inicialización debería fallar según la sección 6.7.8 “Inicialización” del estándar ISO C99.

La más relevante en este caso parece ser la restricción #4 que dice:

Todas las expresiones en un inicializador para un objeto que tiene una duración de almacenamiento estática serán expresiones constantes o literales de cadena.

Entonces, la respuesta a su pregunta es que el código no cumple con el estándar C.

Probablemente desee eliminar la etiqueta “C” si solo estuviera interesado en el estándar C++.

La sección 3.6 en su conjunto es muy clara acerca de la interacción de main e inicializaciones dinámicas. El “inicio designado del programa” no se usa en ningún otro lugar y es solo descriptivo de la intención general de main(). No tiene ningún sentido interpretar esa frase de una manera normativa que contradiga los requisitos más detallados y claros de la Norma.

1646959333 863 ¿Main es realmente el inicio de un programa C
Lundin

El compilador a menudo tiene que agregar código antes de main() para ser compatible con el estándar. Porque el estándar especifica que se debe realizar la inicialización de globales/estáticas antes de se ejecuta el programa. Y como se mencionó, lo mismo ocurre con los constructores de objetos colocados en el ámbito del archivo (globales).

Por lo tanto, la pregunta original es relevante para C también, porque en un programa C aún tendría que hacer la inicialización global/estática antes de que se pueda iniciar el programa.

Los estándares asumen que estas variables se inicializan a través de “magia”, porque no dicen cómo deben establecerse antes de la inicialización del programa. Creo que lo consideraron como algo fuera del alcance de un estándar de lenguaje de programación.

Editar: Véase, por ejemplo, ISO 9899:1999 5.1.2:

Todos los objetos con duración de almacenamiento estático deben inicializarse (establecerse en sus valores iniciales) antes del inicio del programa. La forma y el momento de dicha inicialización no se especifican de otro modo.

La teoría detrás de cómo se debía hacer esta “magia” se remonta al nacimiento de C, cuando era un lenguaje de programación destinado a ser utilizado solo para el sistema operativo UNIX, en computadoras basadas en RAM. En teoría, el programa podría cargar todos los datos preinicializados del archivo ejecutable en la RAM, al mismo tiempo que el programa mismo se cargaba en la RAM.

Desde entonces, las computadoras y el sistema operativo han evolucionado, y C se usa en un área mucho más amplia de lo previsto originalmente. Un sistema operativo de PC moderno tiene direcciones virtuales, etc., y todos los sistemas integrados ejecutan código desde la ROM, no desde la RAM. Entonces, hay muchas situaciones en las que la RAM no se puede configurar “automágicamente”.

Además, el estándar es demasiado abstracto para saber algo sobre las pilas y la memoria de proceso, etc. Estas cosas también deben hacerse antes de iniciar el programa.

Por lo tanto, casi todos los programas C/C++ tienen algún código de inicio/”copia hacia abajo” que se ejecuta antes de que se llame a main, para cumplir con las reglas de inicialización de los estándares.

Como ejemplo, los sistemas integrados suelen tener una opción llamada “inicio no compatible con ISO” donde se omite toda la fase de inicialización por motivos de rendimiento y, a continuación, el código se inicia directamente desde principal. Pero tales sistemas no se ajustan a los estándares, ya que no puede confiar en los valores de inicio de las variables globales/estáticas.

1646959333 621 ¿Main es realmente el inicio de un programa C
Zac Howland

Su “programa” simplemente devuelve un valor de una variable global. Todo lo demás es código de inicialización. Por lo tanto, el estándar se mantiene: solo tiene un programa muy trivial y una inicialización más compleja.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad