Optimiert der Compiler bei einer Funktion, die eine Konstruktstruktur annimmt, nicht den Funktionsrumpf?

Lesezeit: 4 Minuten

Benutzeravatar von Jan Jongboom
Jan Jongboom

Ich habe das folgende Stück Code:

#include <stdio.h>

typedef struct {
    bool some_var;
} model_t;

const model_t model = {
    true
};

void bla(const model_t *m) {
    if (m->some_var) {
        printf("Some var is true!\n");
    }
    else {
        printf("Some var is false!\n");
    }
}

int main() {
    bla(&model);
}

Ich könnte mir vorstellen, dass der Compiler alle erforderlichen Informationen hat, um die zu beseitigen else Klausel in der bla() Funktion. Der einzige Codepfad, der die Funktion aufruft, kommt von main und nimmt sie auf const model_t, also sollte es in der Lage sein, herauszufinden, dass dieser Codepfad nicht verwendet wird. Jedoch:

Ohne Inline

Bei GCC 12.2 sehen wir, dass der zweite Teil eingebunden ist.

Wenn ich inline die Funktion geht aber weg:

Mit Inline

Was fehlt mir hier? Und gibt es eine Möglichkeit, den Compiler dazu zu bringen, intelligenter zu arbeiten? Dies geschieht sowohl in C als auch in C++ mit -O3 und -Os.

  • Der Compiler kann den Else-Pfad nicht wegoptimieren, da die Objektdatei möglicherweise mit anderem Code verknüpft ist. Dies wäre anders, wenn die Funktion statisch wäre.

    – Herr Tux

    29. August um 9:40 Uhr


  • Wenn du machst bla staticCompiler kann es optimieren.

    – Özgür Murat Sağdıçoğlu

    29. August um 9:42 Uhr

  • Der Compiler hat die bla anrufen main und optimiert die else dort abzweigen. Es muss nur die Funktion ausgeben, falls eine andere Übersetzungseinheit sie verwendet. (Der Compiler-Explorer zeigt Ihnen die Ausgabe nach der Kompilierung vor dem Verknüpfen.)

    – Benutzer17732522

    29. August um 9:44 Uhr


  • @Zakk Worauf beziehst du dich? Dass bla war eingebettet? Das Bild in der Frage zeigt die Assembly-Ausgabe des Compilers. Im emittierten main Funktion gibt es keinen Aufruf blanur ein Anruf bei puts mit seinem Argument bedingungslos von geladen .LC0 das ist die Zeichenfolge im ersten Zweig der if. Also wurde die Verzweigung wegoptimiert.

    – Benutzer17732522

    29. August um 13:19 Uhr

  • Ihre Bilder sollten es sein godbolt.org vollständige Links, nicht nur zum Bild auf imgur! Code sollte jedoch nicht in erster Linie als Bilder gepostet werden.

    – Peter Cordes

    30. August um 14:57 Uhr


Benutzeravatar von Ayxan Haqverdili
Ayxan Haqverdili

Der Compiler tut eliminieren Sie den Else-Pfad in der Inline-Funktion in main. Sie verwirren die globale Funktion, die ohnehin nicht aufgerufen wird und schließlich vom Linker verworfen wird.

Wenn Sie die verwenden -fganzes Programm Flag, um den Compiler wissen zu lassen, dass keine andere Datei gelinkt wird, wird dieses unbenutzte Segment verworfen:

[See online]

Geben Sie hier die Bildbeschreibung ein

Darüber hinaus verwenden Sie static oder inline Schlüsselwörter, um etwas Ähnliches zu erreichen.

Benutzeravatar von MrTux
Herr Tux

Der Compiler kann den Else-Pfad nicht wegoptimieren, da die Objektdatei möglicherweise mit anderem Code verknüpft ist. Dies wäre anders, wenn die Funktion statisch wäre oder Sie die Optimierung des gesamten Programms verwenden.

  • Wenn die Funktion deklariert wurde static es würde auch einfach nicht emittiert werden (wie bei inline). Alle Aufrufseiten sind sowieso inline. Die ausgegebene Funktion in der Frage wurde nie verwendet.

    – Benutzer17732522

    29. August um 9:47 Uhr


Der einzige Codepfad, der die Funktion aufruft, kommt von main

GCC kann das nicht wissen, es sei denn, Sie sagen es mit -fwhole-program oder vielleicht -flto (Link-Time-Optimierung). Andernfalls muss es davon ausgehen, dass ein statischer Konstruktor in einer anderen Kompilationseinheit es aufrufen könnte. (Einschließlich möglicherweise in einer gemeinsam genutzten Bibliothek, aber einer anderen .cpp dass Sie mit verknüpfen könnte es tun.) zB

// another .cpp
typedef struct {  bool some_var; } model_t;
void bla(const model_t *m);              // declare the things from the other .cpp

int foo() {
    model_t model = {false};
    bla(&model);
    return 1;
}
int some_global = foo();  // C++ only: non-constant static initializer.

Beispiel auf Godbolt mit diesen Zeilen in derselben Kompilierungseinheit wie main, was zeigt, dass beides ausgegeben wird Some var is false! und dann Some var is true!ohne den Code für geändert zu haben main.

ISO C hat keine einfachen Möglichkeiten, Init-Code auszuführen, aber GNU C (und GCC speziell) haben Möglichkeiten, Code beim Start auszuführen, nicht von aufgerufen main. Dies funktioniert sogar für gemeinsam genutzte Bibliotheken.


Mit -fwhole-programwürde die entsprechende Optimierung einfach gar keine Definition dafür ausgeben, da sie bereits in die Aufrufseite integriert ist main. Wie mit inline (In C++ ein Versprechen, dass jeder andere Aufrufer in einer anderen Kompilierungseinheit seine eigene Definition der Funktion sehen kann) oder static (privat für diese Compilation Unit).

Innen main, es hat die Verzweigung nach ständiger Ausbreitung wegoptimiert. Wenn Sie das Programm ausführen würden, würde tatsächlich keine Verzweigung ausgeführt werden; nichts ruft die eigenständige Definition der Funktion auf.


Die eigenständige Definition der Funktion weiß nicht, dass der einzig mögliche Wert für m ist &model. Wenn Sie das in die Funktion einfügen, könnte es wie erwartet optimiert werden.

Nur -fPIC würde den Compiler zwingen, die Möglichkeit der Symbol-Einfügung in Betracht zu ziehen, also die Definition von const model_t model ist nicht derjenige, der nach dem (dynamischen) Linken wirksam ist. Aber Sie kompilieren Code für eine ausführbare Datei, nicht für eine Bibliothek. (Sie können die Symbolinterposition für eine globale Variable deaktivieren, indem Sie ihr “versteckte” Sichtbarkeit geben, __attribute__((visibility("hidden")))oder verwenden -fvisibility=hidden um dies zum Standard zu machen).

1433220cookie-checkOptimiert der Compiler bei einer Funktion, die eine Konstruktstruktur annimmt, nicht den Funktionsrumpf?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy