Pergunta

Eu estava lendo sobre o SIOF em um livro e deu um exemplo:

//file1.cpp
extern int y;
int x=y+1;

//file2.cpp
extern int x;
int y=x+1;  

Agora minha pergunta é:
No código acima, as seguintes coisas acontecerão?

  1. ao compilar o arquivo1.cpp, o compilador deixa y como está, ou seja, não aloca armazenamento para ele.
  2. o compilador aloca armazenamento para x, mas não o inicializa.
  3. Ao compilar file2.cpp, o compilador deixa x como está, ou seja, não aloca armazenamento para ele.
  4. o compilador aloca armazenamento para y, mas não o inicializa.
  5. Ao vincular o arquivo1.o e o arquivo2.o, agora deixe o arquivo2.o ser inicializado primeiro, então agora:
    X obtém valor inicial de 0?ou não é inicializado?
Foi útil?

Solução

As etapas de inicialização são fornecidas em 3.6.2 "Inicialização de objetos não locais" do padrão C ++:

Passo 1: x e y são zero inicializados antes que qualquer outra inicialização ocorra.

Passo 2: x ou y é dinamicamente inicializado - qual não é especificado pelo padrão. Essa variável receberá o valor 1 uma vez que a outra variável terá sido inicializada zero.

Etapa 3: a outra variável será inicializada dinamicamente, obtendo o valor 2.

Outras dicas

SIOF é basicamente um artefato de tempo de execução, o compilador e o vinculador não têm muito a ver com isso.Considere a função atexit(), ela registra funções a serem chamadas na saída do programa.Muitas implementações de CRT possuem algo semelhante para inicialização de programas, vamos chamá-lo de atinit().

A inicialização dessas variáveis ​​globais requer a execução de código, o valor não pode ser determinado pelo compilador.Assim, o compilador gera trechos de código de máquina que executam a expressão e atribuem o valor.Esses trechos precisam ser executados antes da execução de main().

É aí que entra atinit().Uma implementação CRT comum percorre uma lista de ponteiros de função atinit e executa os trechos de inicialização, em ordem.O problema é a ordem em que as funções são registradas na lista atinit().Embora atexit() tenha uma ordem LIFO bem definida e seja implicitamente determinada pela ordem em que o código chama atexit(), esse não é o caso das funções atinit.A especificação da linguagem não requer um pedido, não há nada que você possa fazer no seu código para especificar um pedido.O SIOF é o resultado.

Uma implementação possível é o compilador emitir ponteiros de função em uma seção separada.O vinculador os mescla, produzindo a lista atinit.Se o seu compilador fizer isso, a ordem de inicialização será determinada pela ordem em que você vincula os arquivos do objeto.Olhe para o arquivo de mapa, você deverá ver a seção atinit se o seu compilador fizer isso.Não será chamado de atinit, mas é provável que haja algum tipo de nome com "init".Dar uma olhada no código-fonte do CRT que chama main() também deve fornecer informações.

A questão toda (e a razão pela qual é chamado de "fiasco") é que é impossível dizer com certeza o que acontecerá em um caso como este.Essencialmente, você está pedindo algo impossível (que duas variáveis ​​sejam cada uma maior que a outra).Como eles não podem fazer isso, o que farão está aberto a algumas questões - eles podem produzir 0/1, ou 1/0, ou 1/2, ou 2/1, ou possivelmente (na melhor das hipóteses) apenas um erro mensagem.

Depende do compilador e pode depender do tempo de execução.Um compilador pode decidir inicializar variáveis ​​estáticas lentamente quando a primeira variável em um arquivo é acessada ou quando cada variável é acessada.Caso contrário, ele inicializará todas as variáveis ​​estáticas por arquivo no momento da inicialização, com a ordem geralmente dependendo da ordem dos links dos arquivos.A ordem dos arquivos pode mudar com base nas dependências ou outras influências dependentes do compilador.

Variáveis ​​estáticas geralmente são inicializadas com zero, a menos que tenham um inicializador constante.Novamente, isso depende do compilador.Portanto, uma dessas variáveis ​​provavelmente será zero quando a outra for inicializada.No entanto, como ambos possuem inicializadores, alguns compiladores podem deixar os valores indefinidos.

Acho que o cenário mais provável seria:

  1. O espaço é alocado para as variáveis ​​e ambas possuem o valor 0.
  2. Uma variável, digamos x, é inicializada e definida com o valor 1.
  3. O outro, digamos y, é inicializado e definido com o valor 2.

Você sempre pode executá-lo e ver.Pode ser que alguns compiladores gerem código que entre em loop infinito.

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