Pergunta

Estou lendo o código fonte CRT, da Microsoft, e eu posso vir acima com o seguinte código, onde a função __initstdio1 será executado antes de rotina main ().

A questão é: como executar algum código antes de entrar na rotina main () no VC (não o código VC ++)?

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

A saída será:

Some code before main!
z = 10
End!

No entanto, eu não sou capaz de entender o código.

Tenho feito algumas google em .CRT $ XIC, mas sem sorte é encontrado. Pode algum perito explicar segmento de código acima para mim, especialmente os seguintes:

  1. O que esta linha _CRTALLOC(".CRT$XIC") static pinit = __initstdio1; média? Qual é o significado da Pinit variável?
  2. Durante a compilação o compilador (cl.exe) lança um aviso dizendo como abaixo:

Microsoft (R) 32-bit C / C ++ Otimizando Compiler versão 15.00.30729.01 para 80x86 Copyright (C) Microsoft Corporation. Todos os direitos 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

O que é as necessidades de ações corretivas a serem feitas para remover a mensagem de aviso?

Agradecemos antecipadamente.


Adicionado:

Eu modifiquei o código e dar-tipo para Pinit como _PIFV. Agora, a mensagem de aviso está desaparecido.

O novo código é a seguinte:

#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;
}
Foi útil?

Solução

Há algumas informações aqui (procurar CRT). O significado da pinit variável é ninguém, é apenas um pedaço de dados colocados no executável, onde o tempo de execução pode encontrá-lo. No entanto, gostaria de aconselhá-lo a dar-lhe um tipo, como este:

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

O aviso vinculador provavelmente apenas avisa que você tem uma função que tem int tipo de retorno, mas não retorna nada (provavelmente você mudaria melhor o tipo de retorno para void).

Outras dicas

Uma maneira simples de fazer isso.

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

Isto é o que _CRTALLOC é definido 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

É uma tabela de coisas para pré-Inicializar, dos quais um ponteiro para seu __initstdio1 função é colocada.

Esta página descrita CRT inicialização:

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

Em C ++, pelo menos, você não precisa de todo esse material implementação específica:

#include <iostream>

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

A a;

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

Eu escrevi um premiado artigo sobre isso no CodeGuru um tempo atrás.

Mesmo em C, há uma necessidade de algum código para ser executado antes main() for inserido, se apenas para transformar a linha de comando para a convenção de chamada C. Na prática, a biblioteca padrão precisa de alguma inicialização, e as necessidades exatas podem variar de compilação a compilação.

O verdadeiro ponto de entrada do programa é definido no momento da ligação, e é geralmente em um módulo chamado algo como crt0 por razões históricas. Como você encontrou, a fonte para esse módulo está disponível nas fontes CRT.

Para inicializações de apoio que são descobertos em tempo de ligação, um segmento especial é usado. Sua estrutura é uma lista de ponteiros de função de assinatura fixa, que serão iteradas no início crt0 e cada função chamada. ligação ++ Esta mesma matriz (ou um muito parecido com ele) de ponteiros de função é usada em um C para ponteiros segure para construtores de objetos globais.

A matriz é preenchida pelo ligante, permitindo que todos os módulos ligados para incluir dados na mesma, os quais são todos concatenados em conjunto para formar o segmento no executável acabado. O único significado para o pinit variável é que é declarado (pelo macro _CRTALLOC()) para ser localizado nesse segmento, e é inicializado para o endereço de uma função a ser chamada durante a inicialização C.

Obviamente, os detalhes deste são extremamente específico da plataforma. Para a programação geral, você provavelmente está melhor servido por envolvimento sua inicialização e seu atual principal dentro de uma nova 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 fins especiais, modificando o módulo crt0 si só ou fazendo truques específicos do compilador para obter funções de inicialização no início adicionais chamados pode ser a melhor resposta. Por exemplo, quando a construção de sistemas embarcados que funcionam a partir ROM sem um carregador do sistema operacional, é comum a necessidade de personalizar o comportamento do módulo crt0 a fim de ter uma pilha em tudo em que empurrar os parâmetros para main(). Nesse caso, não pode haver nenhuma solução melhor do que para modificar crt0 para inicializar o hardware de memória para atender às suas necessidades.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top