Come eseguire del codice prima di entrare nel principale) di routine (in VC?

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

  •  05-09-2019
  •  | 
  •  

Domanda

I sto leggendo il codice sorgente CRT di Microsoft, e posso venire con il seguente codice, in cui verrà eseguita la funzione __initstdio1 prima routine principale ().

La domanda è: come eseguire del codice prima di entrare nella routine principale () in VC (non VC ++ Codice)?

#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;
}

L'output sarà:

Some code before main!
z = 10
End!

Comunque, io non sono in grado di capire il codice.

Ho fatto qualche google su .CRT $ XIC ma senza fortuna è trovato. Può spiegare qualche esperto segmento di codice qui sopra per me, soprattutto i seguenti:

  1. Che cosa significa questa linea _CRTALLOC(".CRT$XIC") static pinit = __initstdio1; significa? Qual è il significato del Pinit variabili?
  2. Durante la compilazione il compilatore (cl.exe) lancia un avviso dicendo, come di seguito:

Microsoft (R) a 32 bit C / C ++ compilatore di ottimizzazione Versione 15.00.30729.01 per 80x86 Copyright (C) Microsoft Corporation. Tutti i diritti riservati.

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

Qual è l'azione correttiva deve essere fatto per rimuovere il messaggio di avviso?

Grazie in anticipo.

Aggiunto:

Ho modificato il codice e dare il tipo di Pinit come _PIFV. Ora il messaggio di avviso non c'è più.

Il nuovo codice è il seguente:

#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;
}
È stato utile?

Soluzione

Ci sono alcune informazioni qui (ricerca di CRT). Il significato di pinit variabile è nulla, è solo un pezzo di dati inseriti nel file eseguibile, in cui il runtime può trovare. Tuttavia, vorrei consigliare di fare un tipo, in questo modo:

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

L'avvertimento linker probabilmente solo avverte di avere una funzione che ha int tipo di ritorno, ma non restituisce nulla (probabilmente è meglio cambiare il tipo di ritorno a void).

Altri suggerimenti

Un modo semplice per farlo.

#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;
}

Questo è ciò che _CRTALLOC è definito come:

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

E 'un tavolo di cose da pre-inizializzare, del quale è posto un puntatore alla funzione __initstdio1.

Questa pagina descritto CRT inizializzazione:

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

In C ++, almeno, non hai bisogno di tutta quella roba specifica implementazione:

#include <iostream>

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

A a;

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

ho scritto un premiato articolo su questo su CodeGuru qualche tempo fa.

Anche in C, v'è la necessità per un po 'di codice da eseguire prima viene immesso main(), se non altro per trasformare la linea di comando nella convenzione di chiamata C. In pratica, la libreria standard ha bisogno di un po 'di inizializzazione, e le esigenze specifiche può variare da compilare per la compilazione.

Il vero punto di ingresso programma è impostato in fase di collegamento, e di solito è in un modulo con un nome simile crt0 per ragioni storiche. Come hai trovato, la fonte di tale modulo è disponibile nelle fonti CRT.

Per supportare inizializzazioni che vengono scoperti in fase di collegamento, viene utilizzato un segmento speciale. La sua struttura è una lista di puntatori a funzione di firma fissa, che verrà ripetuta all'inizio del crt0 e ogni funzione chiamata. Questo stesso array (o uno molto simile) di puntatori a funzione è utilizzato in collegamento un C ++ per contenere i puntatori ai costruttori di oggetti globali.

L'array è compilato dal linker consentendo ogni modulo legato per includere i dati in esso, che sono tutti concatenati insieme per formare il segmento nell'eseguibile finito. L'unico significato per l'pinit variabile è che esso è dichiarato (dalla macro _CRTALLOC()) per essere collocata in quel segmento, e viene inizializzato per l'indirizzo di una funzione da chiamare durante l'avvio C.

Ovviamente, i dettagli di questo sono estremamente specifico per la piattaforma. Per la programmazione generale, si sono probabilmente meglio servita avvolgendo l'inizializzazione e il vostro principale corrente all'interno di un nuovo main():

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

Per scopi speciali, modificando il modulo crt0 stesso o fare trucchi specifiche del compilatore per ottenere ulteriori funzioni di inizializzazione presto chiamati può essere la migliore risposta. Ad esempio, nella costruzione di sistemi integrati che vengono eseguiti da ROM senza caricatore del sistema operativo, è comune bisogno di personalizzare il comportamento del modulo crt0 al fine di avere una pila affatto su cui spingere i parametri main(). In tal caso, ci può essere una soluzione migliore di modificare crt0 per inizializzare l'hardware di memoria per soddisfare le vostre esigenze.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top