statische Inline-Funktionen in einer Header-Datei

Lesezeit: 5 Minuten

Benutzer-Avatar
lernenlernen

In letzter Zeit habe ich versucht, mehr Open-Source-C-Code zu lesen. Ein gängiges Muster, das ich in meinen Hobbyprojekten übernommen habe, ist wie folgt.

In meinen C-Dateien habe ich Funktionen, die entweder statisch oder exportiert sind. Nur exportierte Funktionen werden in eine Header-Datei gestellt. Als statische globale Variablen werden auch globale Variablen verwendet, die nur im Rahmen eines Objekts verwendet werden.

Meine Frage betrifft den Nutzen und die Motivation des Habens static inline Funktionen in Header-Dateien. Von dem, was ich online gelesen habe, verwende ich das nicht static Das Schlüsselwort verursacht einen Mehrfachdefinitionsfehler, und das ist der Grund dafür, dass die Funktion nicht einfach als gerecht definiert wird inline.

Bedeutet dies jedoch, dass diese Funktion für andere Objekte zur Verwendung exportiert wird? Wenn ja, warum dann nicht einfach diese Funktion in der C-Datei definieren und über die Header-Datei exportieren? Wenn nicht, warum diese in die Header-Datei einfügen, anstatt sie nur in der C-Datei zu haben?

Gibt es einen Grund für diesen Codierungsstil? Was vermisse ich?

Ein solches Beispiel kann in der Git-Codebasis im Inneren gefunden werden hashmap.h:

/*
 * Converts a cryptographic hash (e.g. SHA-1) into an int-sized hash code
 * for use in hash tables. Cryptographic hashes are supposed to have
 * uniform distribution, so in contrast to `memhash()`, this just copies
 * the first `sizeof(int)` bytes without shuffling any bits. Note that
 * the results will be different on big-endian and little-endian
 * platforms, so they should not be stored or transferred over the net.
 */
static inline unsigned int sha1hash(const unsigned char *sha1)
{
    /*
     * Equivalent to 'return *(unsigned int *)sha1;', but safe on
     * platforms that don't support unaligned reads.
     */
    unsigned int hash;
    memcpy(&hash, sha1, sizeof(hash));
    return hash;
}

  • Als Referenz: stackoverflow.com/help/mcve

    – Fabelhaft

    14. Dezember 2017 um 18:35 Uhr

  • Meinst du mit “exportiert” “extern”? Meinst du vielleicht konkreter “deklariert mit an extern Speicherklassenbezeichner”?

    – Johannes Bollinger

    14. Dezember 2017 um 18:36 Uhr

  • Seien Sie sich auf jeden Fall bewusst, dass es bereits solche gibt viele Fragen (mit Antworten) zu C-Inline-Funktionen hier auf SO. Sind Sie sicher, dass Ihre sinnvoll getrennt ist?

    – Johannes Bollinger

    14. Dezember 2017 um 18:40 Uhr

  • Mit “exportiert” meine ich eine Funktion, die von einer anderen Objektdatei verwendet werden kann. Sie könnten Funktionen sein, die in einer C-Datei definiert und in einer Header-Datei deklariert sind und nicht unbedingt das Schlüsselwort “extern” verwenden. Ich habe eine Bearbeitung vorgenommen. Ich habe einige Fragen zu “Static Inline” gesehen, aber sie schienen meine Frage nicht zu beantworten. Meine Frage ist ein Versuch zu verstehen, warum sich das obige Code-Snippet in einer Header-Datei im Gegensatz zu einer C-Datei befindet. Ich glaube, ich habe auch ähnlichen Code im Linux-Kernel-Code gesehen.

    – lernenlernenlernen

    14. Dezember 2017 um 20:07 Uhr

  • Beachten Sie, dass es einen großen Unterschied zwischen der Definition von Ebene gibt static Funktionen in Header-Dateien (möglicherweise ein Fehler) und static inline Funktionen (wahrscheinlich eine gute Idee, wenn die Funktionen inline-fähig sind). Wenn die Funktion zu groß oder zu komplex ist, um inline erstellt zu werden, erhalten Sie am Ende eine Kopie der Funktion in jeder Objektdatei (und Sie erhalten Warnungen, wenn die Funktion nicht verwendet wird, während Sie dies bei Inline-Funktionen nicht tun).

    – Jonathan Leffler

    14. Dezember 2017 um 20:26 Uhr

Benutzer-Avatar
Basile Starynkevitch

EIN static inline Funktion ist in der Praxis wahrscheinlich (aber nicht sicher) zu sein eingebettet von einem guten optimierenden Compiler (zB by GCC wenn es gegeben ist -O2) an den meisten seiner Aufrufseiten.

Es wird in einer Header-Datei definiert, weil es dann bei den meisten Aufrufseiten (vielleicht allen) inline sein könnte. Wenn es nur so wäre erklärt (und einfach “exportiert”), ist es unwahrscheinlich, dass das Inlining stattfindet (außer wenn Sie kompilieren und verlinken mit Link-Time-Optimierungenauch bekannt als LTO, zB kompilieren und verknüpfen mit gcc -flto -O2und das nimmt zu viel die Bauzeit).

In der Praxis muss der Compiler den Rumpf einer Funktion kennen, um sie einbetten zu können. Ein geeigneter Ort ist es also, es in einer gemeinsamen Header-Datei zu definieren (andernfalls könnte es nur in dieselbe Übersetzungseinheit eingebettet werden, die es definiert, es sei denn, Sie aktivieren LTO), sodass jede Übersetzungseinheit den Körper dieser inlinierbaren Funktion kennt.

Es ist deklariert static um mehrfache Definitionen (zur Verbindungszeit) zu vermeiden, falls der Compiler sie nicht eingefügt hat (z. B. wenn Sie ihre Adresse verwenden).

In der Praxis würde ich in C99- oder C11-Code (außer bei LTO, das ich selten verwende) immer die kurzen Funktionen einfügen, als die ich inliniert werden möchte static inline Definitionen in gemeinsamen Header-Dateien.

Achten Sie darauf, zu verstehen, wie und wann die C-Präprozessor funktioniert. Beachten Sie, dass Sie im Prinzip (aber es wäre eine sehr schlechte Übung und ein widerlicher Stil) vermeiden könnten, einige zu definieren static inline Funktion in einer gemeinsamen Header-Datei und kopieren und fügen Sie stattdessen ihre identische Definition in mehreren ein .c Dateien. (Allerdings könnte das sinnvoll sein generiert .c Dateien, zB wenn Sie eine entwerfen Compiler, der C-Code ausgibt).

FYI LTO wird von neueren GCC-Compilern praktisch implementiert, indem einige interne Compiler-Darstellungen (einige GIMPLE) in Objektdateien und Wiederholen einiger “Kompilierungs” -Schritte – Verwendung der lto1 Frontend – zur “Link”-Zeit. In der Praxis wird das gesamte Programm fast “zweimal” kompiliert.

(Eigentlich habe ich mich immer gefragt, warum das C-Standardisierungsgremium nicht stattdessen alles explizit entschieden hat inline Funktionen sind statisch)

  • Wahrscheinlich ist der Unterschied zu C++ erwähnenswert inline wrt die static Ding (Spoiler: Ich vergesse ständig die Details, daher wäre ich jedem sehr dankbar, der eine gute Zusammenfassung gibt).

    – Matteo Italien

    14. Dezember 2017 um 20:50 Uhr

  • Schöne Erklärung. Das ist die Praxis, eine Funktionsdefinition in eine Header-Datei zu schreiben.

    – Chao

    19. Oktober 2021 um 12:00 Uhr

1368400cookie-checkstatische Inline-Funktionen in einer Header-Datei

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

Privacy policy