AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 77495376
Accepted
blonded04
blonded04
Asked: 2023-11-16 21:49:43 +0800 CST2023-11-16 21:49:43 +0800 CST 2023-11-16 21:49:43 +0800 CST

O fiasco da ordem de inicialização estática é aplicável a C?

  • 772

Tudo o que encontrei na Internet sobre o fiasco da ordem de inicialização estática era sobre C++, mas é verdade que se eu inicializar uma variável global de algum tipo Foo como

struct Foo {
    int flag;
    pthread_key_t key;
    void *ptrs[10];
};

Não consigo inicializar uma variável do tipo struct Foocomo static struct Foo x = { 0 };? se eu quiser obter o código correto por causa do SIOF?

c++
  • 4 4 respostas
  • 141 Views

4 respostas

  • Voted
  1. dbush
    2023-11-16T21:52:36+08:002023-11-16T21:52:36+08:00

    O problema com a inicialização em C++ é que o código executável pode ser executado antes da mainfunção, portanto, nem sempre é claro em que ordem esse código será executado. Isso é necessário em C++ devido aos construtores para objetos estáticos.

    C, por outro lado, não permite que o código seja executado fora de uma função. Os inicializadores para objetos estáticos devem ser expressões constantes que podem ser calculadas em tempo de compilação.

    Isso significa que um inicializador como static struct Foo x = { 0 };é perfeitamente adequado em C.

    • 6
  2. Best Answer
    Lundin
    2023-11-16T23:21:35+08:002023-11-16T23:21:35+08:00

    Para objetos com duração de armazenamento estático (e thread), C apenas afirma que eles são inicializados em algum ponto antes de main() ser chamado. C apenas permite que eles sejam inicializados com expressões constantes. Já em C++, os objetos podem ter construtores e podem ser inicializados com o resultado de uma função.

    Se espiarmos "por baixo do capô" do código "C runtime" (CRT) que é executado antes de main() ser chamado, no que diz respeito às variáveis, ele inicializará apenas .dataand .bss. A partir daí, ele está pronto para funcionar. O tempo de execução C++ equivalente não é tão trivial, porque também inicia chamadas de construtor, etc. Como nenhuma ordem específica é especificada nem pelo padrão C++ nem pelo programador, o CRT apenas os chamará em alguma ordem subjetiva de aparência. Se houver dependências de ordem de inicialização entre objetos nesse ponto, tudo logo desmoronará.

    C++ também adicionou complexidade adicional ao definir a inicialização estática como tudo que se enquadra em duas subcategorias: inicialização constante e inicialização zero . E então nomeia todo o resto como inicialização dinâmica (não deve ser confundida com alocação dinâmica). A inicialização dinâmica, por sua vez, vem com conceitos de ordem de aparecimento, sequência e assim por diante.

    • 1
  3. jxh
    2023-11-17T00:31:23+08:002023-11-17T00:31:23+08:00

    No contexto de como você deseja inicializar sua estrutura com zero, não há problema.

    No entanto, no caso geral, o problema pode ocorrer no código C ao abrir .sobibliotecas, também conhecidas como bibliotecas compartilhadas. Isso ocorre porque as bibliotecas compartilhadas podem incluir uma .initseção de código que é executada quando a biblioteca é carregada.

    Então, você deve imaginar duas bibliotecas compartilhadas que se referem às estruturas de dados uma da outra dentro de suas rotinas de inicialização.

    É certo que isso está fora do escopo da linguagem C. No entanto, é relevante no contexto de um vinculador ao lidar com bibliotecas compartilhadas.

    • 1
  4. Brian Bi
    2023-11-17T09:23:36+08:002023-11-17T09:23:36+08:00

    C não tem o fiasco da ordem de inicialização estática. Em C89, a regra era:

    Todas as expressões em um inicializador para um objeto que possui duração de armazenamento estático ou em uma lista de inicializadores para um objeto que possui tipo agregado ou união devem ser expressões constantes.

    Portanto, uma variável estática com tipo escalar só poderia ser inicializada com uma única expressão constante. Se o tipo da variável for um array com um tipo de elemento escalar, então cada inicializador precisaria ser uma expressão constante e assim por diante. Como uma expressão constante não pode produzir efeitos colaterais nem depender de efeitos colaterais produzidos por qualquer outra avaliação, alterar a ordem de avaliação das expressões constantes não afeta o resultado. Além disso, o compilador pode simplesmente emitir dados já inicializados (ou seja, avaliar essas expressões constantes em tempo de compilação), portanto, quando o programa for iniciado, não haverá inicialização estática a ser feita.

    As únicas expressões não constantes que podem ser avaliadas antes mainsão aquelas invocadas no tempo de execução C. É por isso que os FILEobjetos apontados por stdin, stdoute stderrjá estão disponíveis para uso pela primeira instrução de main, por exemplo. O C padrão não permite que os usuários registrem seu próprio código de inicialização para ser executado antes main- embora o GCC forneça uma extensão chamada __constructor__(presumivelmente nomeada após o recurso C++) que você pode usar para recriar o fiasco da ordem de inicialização estática em C, se desejar. .

    Stroustrup escreveu em The Design and Evolution of C++ que seu objetivo era tornar os tipos definidos pelo usuário utilizáveis ​​onde quer que estivessem os tipos integrados. Isso significava que o C++ tinha que permitir variáveis ​​globais do tipo classe, o que significa que seus construtores seriam chamados durante a inicialização do programa. Como o C++ antigo não tinha constexprfunções, essas chamadas de construtor nunca poderiam ser expressões constantes. E assim nasceu o fiasco da ordem de inicialização estática.

    Durante o processo de padronização do C++, a questão da ordem de execução da inicialização estática foi um tema controverso. Acho que a maioria das pessoas concordaria que o idealsituação seria que cada variável estática fosse inicializada antes de seu uso. Infelizmente, isso requer tecnologia de linker que não existia naquela época (e provavelmente ainda não existe?). A inicialização de uma variável estática pode envolver chamadas de função, e essas funções podem ser definidas em outra TU, o que significa que você precisaria realizar uma análise de todo o programa para classificar topologicamente com sucesso as variáveis ​​estáticas em ordem de dependência. É importante notar que mesmo que o C++ pudesse ter sido projetado dessa maneira, ainda assim não teria evitado completamente os problemas de ordem de inicialização. Imagine se você tivesse alguma biblioteca onde uma pré-condição da usefunção fosse que ela inittivesse sido chamada em algum momento no passado. Então, se você tiver uma variável estática cujo inicializador chamainite outro cujo inicializador chama use, então há uma dependência de ordem que o compilador não consegue ver.

    Em última análise, as garantias limitadas de ordem de inicialização que obtivemos no C++ 98 foram as melhores que pudemos obter nessas circunstâncias. Com o benefício de uma retrospectiva ilimitada, talvez alguém pudesse ter protestado que o padrão não estaria completo sem constexprfunções (e que as variáveis ​​estáticas deveriam ser obrigadas a ter apenas inicialização constante).

    • 0

relate perguntas

  • Por que os compiladores perdem a vetorização aqui?

  • Erro de compilação usando CMake com biblioteca [fechada]

  • Erro lançado toda vez que tento executar o premake

  • Como criar um tipo de octeto semelhante a std::byte em C++?

  • Somente operações bit a bit para std::byte em C++ 17?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    destaque o código em HTML usando <font color="#xxx">

    • 2 respostas
  • Marko Smith

    Por que a resolução de sobrecarga prefere std::nullptr_t a uma classe ao passar {}?

    • 1 respostas
  • Marko Smith

    Você pode usar uma lista de inicialização com chaves como argumento de modelo (padrão)?

    • 2 respostas
  • Marko Smith

    Por que as compreensões de lista criam uma função internamente?

    • 1 respostas
  • Marko Smith

    Estou tentando fazer o jogo pacman usando apenas o módulo Turtle Random e Math

    • 1 respostas
  • Marko Smith

    java.lang.NoSuchMethodError: 'void org.openqa.selenium.remote.http.ClientConfig.<init>(java.net.URI, java.time.Duration, java.time.Duratio

    • 3 respostas
  • Marko Smith

    Por que 'char -> int' é promoção, mas 'char -> short' é conversão (mas não promoção)?

    • 4 respostas
  • Marko Smith

    Por que o construtor de uma variável global não é chamado em uma biblioteca?

    • 1 respostas
  • Marko Smith

    Comportamento inconsistente de std::common_reference_with em tuplas. Qual é correto?

    • 1 respostas
  • Marko Smith

    Somente operações bit a bit para std::byte em C++ 17?

    • 1 respostas
  • Martin Hope
    fbrereto Por que a resolução de sobrecarga prefere std::nullptr_t a uma classe ao passar {}? 2023-12-21 00:31:04 +0800 CST
  • Martin Hope
    比尔盖子 Você pode usar uma lista de inicialização com chaves como argumento de modelo (padrão)? 2023-12-17 10:02:06 +0800 CST
  • Martin Hope
    Amir reza Riahi Por que as compreensões de lista criam uma função internamente? 2023-11-16 20:53:19 +0800 CST
  • Martin Hope
    Michael A formato fmt %H:%M:%S sem decimais 2023-11-11 01:13:05 +0800 CST
  • Martin Hope
    God I Hate Python std::views::filter do C++20 não filtrando a visualização corretamente 2023-08-27 18:40:35 +0800 CST
  • Martin Hope
    LiDa Cute Por que 'char -> int' é promoção, mas 'char -> short' é conversão (mas não promoção)? 2023-08-24 20:46:59 +0800 CST
  • Martin Hope
    jabaa Por que o construtor de uma variável global não é chamado em uma biblioteca? 2023-08-18 07:15:20 +0800 CST
  • Martin Hope
    Panagiotis Syskakis Comportamento inconsistente de std::common_reference_with em tuplas. Qual é correto? 2023-08-17 21:24:06 +0800 CST
  • Martin Hope
    Alex Guteniev Por que os compiladores perdem a vetorização aqui? 2023-08-17 18:58:07 +0800 CST
  • Martin Hope
    wimalopaan Somente operações bit a bit para std::byte em C++ 17? 2023-08-17 17:13:58 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve