La forma de ejecutar algún código antes de entrar en la rutina principal () en VC?

StackOverflow https://stackoverflow.com/questions/728939

  •  05-09-2019
  •  | 
  •  

Pregunta

Estoy leyendo el código fuente CRT de Microsoft, y que puede llegar con el siguiente código, donde el __initstdio1 función se ejecutará antes de rutina principal ().

La pregunta es, cómo ejecutar algún código antes de entrar en la rutina principal () en VC (no VC ++ código)?

#include <stdio.h>

#pragma section(".CRT$XIC",long,read)

int __cdecl __initstdio1(void);

#define _CRTALLOC(x) __declspec(allocate(x))

_CRTALLOC(".CRT$XIC") static pinit = __initstdio1;

int z = 1;

int __cdecl __initstdio1(void) {
    z = 10;
    return 0;
}

int main(void) {
    printf("Some code before main!\n");
    printf("z = %d\n", z);
    printf("End!\n");
    return 0;
}

La salida será:

Some code before main!
z = 10
End!

Sin embargo, no soy capaz de entender el código.

He hecho un poco de Google en .CRT $ XIC, pero no se encuentra ninguna suerte. Puede explicar por algún experto segmento de código anterior para mí, especialmente los siguientes:

  1. ¿Qué significa esto _CRTALLOC(".CRT$XIC") static pinit = __initstdio1; línea? ¿Cuál es el significado de la Pinit variable?
  2. Durante la compilación el compilador (cl.exe) lanza un aviso que dice de la siguiente manera:

Microsoft (R) 32-bit C / C ++ compilador de optimización Version 15.00.30729.01 para 80x86 Copyright (C) Microsoft Corporation. Todos los derechos reservados.

stdmacro.c
stdmacro.c(9) : warning C4047: 'initializing' : 'int' differs in levels of indirection from 'int (__
cdecl *)(void)'
Microsoft (R) Incremental Linker Version 9.00.30729.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:stdmacro.exe
stdmacro.obj

¿Cuál es la acción correctiva que hay que hacer para eliminar el mensaje de advertencia?

Gracias de antemano.


Alta:

He modificado el código y darle al tipo PINIT como _PIFV. Ahora el mensaje de advertencia se ha ido.

El nuevo código es el siguiente:

#include <stdio.h>

#pragma section(".CRT$XIC1",long,read)

int __cdecl __initstdio1(void);

typedef int  (__cdecl *_PIFV)(void);

#define _CRTALLOC(x) __declspec(allocate(x))

_CRTALLOC(".CRT$XIC1") static _PIFV pinit1 = __initstdio1;

int z = 1;

int __cdecl __initstdio1(void) {
    z = 100;

    return 0;
}

int main(void) {
    printf("Some code before main!\n");
    printf("z = %d\n", z);
    printf("End!\n");
    return 0;
}
¿Fue útil?

Solución

Hay alguna información aquí (búsqueda de CRT). La importancia de pinit variable es ninguna, que es sólo una parte de los datos colocados en el ejecutable, en el que el tiempo de ejecución puede encontrarlo. Sin embargo, yo le aconsejo que para darle un tipo, como esto:

_CRTALLOC(".CRT$XIC") static void (*pinit)()=...

La advertencia enlazador probablemente sólo advierte que tiene una función que ha int tipo de retorno, pero no devuelve nada (probablemente será mejor que cambiar el tipo de retorno a void).

Otros consejos

Una forma sencilla de hacer esto.

#include <iostream>

int before_main()
{
    std::cout << "before main" << std::endl;
    return 0;
}

static int n = before_main();

void main(int argc, char* argv[])
{
    std::cout << "in main" << std::endl;
}

Esto es lo que _CRTALLOC se define como:

extern _CRTALLOC(".CRT$XIA") _PVFV __xi_a[];
extern _CRTALLOC(".CRT$XIZ") _PVFV __xi_z[];// C initializers
extern _CRTALLOC(".CRT$XCA") _PVFV __xc_a[];
extern _CRTALLOC(".CRT$XCZ") _PVFV __xc_z[];// C++ initializers

Es una tabla de comprobar la validez de las cosas inicializar, de los cuales se coloca un puntero a su __initstdio1 función.

Esta página se describe la inicialización CRT:

http://msdn.microsoft.com/en-us/library /bb918180.aspx

En C ++, al menos, que no es necesario todo eso específica aplicación:

#include <iostream>

struct A {
   A() { std::cout << "before main" << std::endl; }
};

A a;

int main() {
   std::cout << "in main" << std::endl;
}

escribí un galardonado artículo sobre esto en CodeGuru hace un tiempo.

Incluso en C, hay una necesidad de un código que se ejecute antes de entrar en main(), aunque sólo sea para transformar la línea de comando en la convención de llamada C. En la práctica, la biblioteca estándar necesita un poco de inicialización, y las necesidades exactas pueden variar de compilación para compilar.

El verdadero punto de entrada del programa se establece en tiempo de enlace, y es por lo general en un módulo llamado algo así como crt0 por razones históricas. Como has encontrado, la fuente de ese módulo está disponible en las fuentes de CRT.

Para apoyar inicializaciones que se descubren en tiempo de enlace, se utiliza un segmento especial. Su estructura es una lista de punteros a funciones de la firma fijo, el cual se repitan ciertos principios de crt0 y cada función llamada. Este mismo array (o uno muy parecido a él) de punteros de función se utiliza en enlace un C ++ para contener punteros a constructores de objetos globales.

la matriz es rellenado por el enlazador al permitir que cada módulo vinculado a incluir datos en ella, los cuales están concatenados juntos para formar el segmento en el ejecutable final. La única importancia para el pinit variable es que se declara (por la macro _CRTALLOC()) que se encuentra en ese segmento, y se inicializa a la dirección de una función a ser llamada durante el inicio C.

Obviamente, los detalles de esta plataforma son muy específicos. Para la programación general, usted es probablemente mejor servido por envolver su inicialización y su corriente principal dentro de un nuevo main():

int main(int argc, char **argv) {
    early_init();
    init_that_modifies_argv(&argc, &argv);
    // other pre-main initializations...
    return real_main(argc,argv);
}

Para efectos especiales, modificando el módulo crt0 sí mismo o haciendo trucos específicas del compilador para obtener funciones adicionales a principios de inicialización llamado puede ser la mejor respuesta. Por ejemplo, en la construcción de sistemas integrados que se ejecutan desde la ROM sin un cargador del sistema operativo, es común a necesitar para personalizar el comportamiento del módulo crt0 con el fin de tener una pila en absoluto en el que para empujar los parámetros a main(). En ese caso, puede que no haya mejor solución que modificar crt0 para inicializar el hardware de memoria para satisfacer sus necesidades.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top