Frage

Ich arbeite an einem C ++ - Code und bin auf eine Frage gestoßen, die mich schon seit einiger Zeit nagte ... vorausgesetzt genannt?

Ich habe gehört, dass es in crtBegin.o eine Funktion gibt, und eine Funktion _fini in crtend.o. Werden diese von crt0.o genannt? Oder erkennt der dynamische Linker ihre Anwesenheit in der geladenen Binärin und ruft sie an? Wenn ja, Wenn Ruft es sie tatsächlich an?

Ich bin hauptsächlich daran interessiert zu wissen, dass ich verstehen kann, was hinter den Kulissen passiert, wenn mein Code geladen, ausgeführt und dann zur Laufzeit entladen wird.

Danke im Voraus!

UPDATE: Ich versuche im Grunde genommen herauszufinden, die allgemeine Zeit zu ermitteln, zu der die Konstruktoren aufgerufen werden. Ich möchte keine Annahmen in meinem Code auf der Grundlage dieser Informationen treffen. Es ist mehr oder weniger, ein besseres Verständnis dafür zu bekommen, was auf den niedrigeren Ebenen passiert, wenn mein Programm geladen wird. Ich verstehe, dass dies ziemlich osspezifisch ist, aber ich habe versucht, es in dieser Frage ein wenig einzugrenzen.

War es hilfreich?

Lösung

Wenn Sie über nicht lokale statische Objekte sprechen, gibt es nicht viele Garantien. Wie Sie bereits wissen (und es wurde auch hier erwähnt), sollte es keinen Code schreiben, der davon abhängt. Das Fiasko der statischen Initialisierungsordnung ...

Statische Objekte durchlaufen eine Zweiphaseninitialisierung: statische Initialisierung und dynamische Initialisierung. Ersteres erfolgt zuerst und führt durch konstante Ausdrücke null Initialisierung oder Initialisierung durch. Letzteres tritt nach, nachdem alle statischen Initialisierung durchgeführt wurde. Dies ist, wenn Konstruktoren zum Beispiel aufgerufen werden.

Im Allgemeinen erfolgt diese Initialisierung irgendwann vor Main (). Im Gegensatz zu dem, was viele Menschen glauben, dass dies nicht durch den C ++ - Standard garantiert wird. In der Tat garantiert ist, dass die Initialisierung vor der Verwendung einer Funktion oder eines Objekts durchgeführt wird, die in derselben Übersetzungseinheit wie das initialisierte Objekt definiert sind. Beachten Sie, dass dies nicht osspezifisch ist. Dies sind C ++ - Regeln. Hier ist ein Zitat aus dem Standard:

Es ist implementiert definiert, ob die dynamische Initialisierung (8.5, 9.4, 12.1, 12.6.1) eines Objekts des Namespace-Bereichs vor der ersten Anweisung von Main durchgeführt wird. Wenn die Initialisierung nach der ersten Hauptaussage bis zu einem bestimmten Zeitpunkt aufgeschoben wird, erfolgt sie vor der ersten Verwendung einer Funktion oder eines Objekts, die in derselben Übersetzungseinheit wie das zu initialisierte Objekt definiert sind

Andere Tipps

Dies ist nicht osspezifisch, sondern der Compilerspezifische.

Sie haben die Antwort gegeben, die Initialisierung erfolgt in __init.

Für den zweiten Teil können Sie in GCC die Reihenfolge der Initialisierung mit a garantieren ____attribute____((init_priority(PRIORITY))) an eine variable Definition beigefügt, wo PRIORITY ist ein relativer Wert, wobei die niedrigeren Zahlen zuerst initialisiert wurden.

Dies hängt schwer von Compiler und Laufzeit ab. Es ist keine gute Idee, Annahmen zu den Zeiten, die globale Objekte aufgebaut sind, zu treffen.

Dies ist insbesondere ein Problem, wenn Sie ein statisches Objekt haben, das von einem anderen abhängt, der bereits konstruiert wird.

Das nennt man "Statische Initialisierungsauftragsfiasko". Auch wenn dies in Ihrem Code nicht der Fall ist, sind die FAQ -Artikel von C ++ Lite zu diesem Thema eine Lektüre wert.

Die Stipendiaten, die Sie haben:

  • Alle statischen nicht-lokalen Objekte im globalen Namespace werden vor Main () konstruiert ()
  • Alle statischen nicht-lokalen Objekte in einem anderen Namespace werden konstruiert, bevor alle Funktionen/Methoden in diesem Namespace verwendet werden (sodass der Compiler sie möglicherweise faul bewerten kann [aber nicht auf dieses Verhalten zählen]).
  • Alle statischen nicht-lokalen Objekte in einer Übersetzungseinheit sind in der Reihenfolge der Deklaration konstruiert.
  • Über die Reihenfolge zwischen Übersetzungseinheiten ist nichts definiert.
  • Alle statischen nicht-lokalen Objekte werden in umgekehrter Reihenfolge der Schöpfung zerstört. (Dazu gehören die statischen Funktionsvariablen (die bei der ersten Verwendung faul erstellt werden).

Wenn Sie Globale haben, die Abhängigkeiten voneinander haben, haben Sie zwei Optionen:

  • Setzen Sie sie in die gleiche Übersetzungseinheit.
  • Verwandeln Sie sie in statische Funktionsvariablen, die beim ersten Gebrauch abgerufen und konstruiert wurden.

Beispiel 1: Der Global A -Konstruktor verwendet globales Protokoll

class AType
{    AType()  { log.report("A Constructed");}};

LogType    log;
AType      A;

// Or 
Class AType() 
{    AType()  { getLog().report("A Constructed");}};
LogType& getLog()
{
    static LogType  log;
    return log;
}
// Define A anywhere;

Beispiel Global Bs Destruktor verwendet globales Protokoll

Hier müssen Sie veranlassen, dass das Objektprotokoll nicht vor dem Objekt B zerstört wird. Dies bedeutet, dass das Protokoll vor B vollständig konstruiert werden muss (wie die umgekehrte Reihenfolge der Zerstörungsregel dann gilt). Auch hier können die gleichen Techniken angewendet werden. Stecken Sie sie entweder in die gleiche Übersetzungseinheit oder verwenden Sie eine Funktion, um Protokoll zu erhalten.

class BType
{    ~BType()  { log.report("B Destroyed");}};

LogType    log;
BType      B;   // B constructed after log (so B will be destroyed first)

// Or 
Class BType() 
{    BType()    { getLog();}
     /*
      * If log is used in the destructor then it must not be destroyed before B
      * This means it must be constructed before B 
      * (reverse order destruction guarantees that it will then be destroyed after B)
      *
      * To achieve this just call the getLog() function in the constructor.
      * This means that 'log' will be fully constructed before this object.
      * This means it will be destroyed after and thus safe to use in the destructor.
      */
    ~BType()    { getLog().report("B Destroyed");}
};
LogType& getLog()
{
    static LogType  log;
    return log;
}
// Define B anywhere;

Gemäß dem C ++ - Standard werden sie aufgerufen, bevor eine Funktion oder ein Objekt ihrer Übersetzungseinheit verwendet wird. Beachten Sie, dass für Objekte im globalen Namespace dies bedeuten würde, dass sie zuvor initialisiert werden main() wird genannt. (Sehen ltcmelo und Martin Antworten für Mote -Details und eine Diskussion darüber.)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top