statische Funktion in C

Lesezeit: 8 Minuten

Benutzeravatar von Cenoc
Cenoc

Was bringt es, eine Funktion in C statisch zu machen?

  • @nightcracker: In C++ gibt es keine “Methoden”. Ich glaube, Sie sind mit Objective-C verwechselt.

    – Bo Persson

    16. März 2011 um 16:17 Uhr

  • Nein, ich bin verwirrt mit Python. Eine Funktion innerhalb einer Klasse wird in Python als Methode bezeichnet.

    – orlp

    16. März 2011 um 16:25 Uhr

  • mögliches Duplikat von Was ist eine “statische” Funktion? (in C)

    – atoMerz

    7. März 2014 um 11:53 Uhr

Benutzeravatar von pmg
pmg

Funktion machen static verbirgt es vor anderen Übersetzungseinheiten, was zur Bereitstellung beiträgt Verkapselung.

helper_file.c

int f1(int);        /* prototype */
static int f2(int); /* prototype */

int f1(int foo) {
    return f2(foo); /* ok, f2 is in the same translation unit */
                    /* (basically same .c file) as f1         */
}

int f2(int foo) {
    return 42 + foo;
}

Haupt c:

int f1(int); /* prototype */
int f2(int); /* prototype */

int main(void) {
    f1(10); /* ok, f1 is visible to the linker */
    f2(12); /* nope, f2 is not visible to the linker */
    return 0;
}

  • Ist die Übersetzungseinheit hier die richtige Terminologie? Wäre die Objektdatei nicht genauer? Soweit ich weiß, ist eine statische Funktion vor dem Linker verborgen und der Linker arbeitet nicht mit Übersetzungseinheiten.

    – Steven Eckhoff

    13. Februar 2014 um 18:32 Uhr

  • Ich hätte auch sagen sollen, dass ich es mir gerne so vorstelle, dass es vor dem Linker verborgen ist; es scheint so klarer.

    – Steven Eckhoff

    13. Februar 2014 um 18:51 Uhr

  • Also, interne Funktion (die wir sicher nicht außerhalb ihrer c-Datei aufrufen), sollten wir sie als statische Funktion setzen, richtig? Wir können also sicher sein, dass es nicht woanders anrufen kann. Vielen Dank 🙂

    – Hqt

    6. Juli 2014 um 3:30 Uhr

  • Wie kompiliert man das? Benutzt du #include <helper_file.c>? Ich denke, das würde es dann zu einer einzigen Übersetzungseinheit machen …

    – Kalt

    23. August 2016 um 1:30 Uhr


  • @Atcold: So wie ich den Code geschrieben habe, fügen Sie einfach die 2 Quelldateien wie folgt in die Befehlszeile ein gcc -std=c99 -pedantic -Wall -Wextra main.c helper_file.c. Die Prototypen für die Funktionen sind in beiden Quelldateien vorhanden (keine Notwendigkeit für Header-Dateien). Der Linker löst die Funktionen auf.

    – pmg

    23. August 2016 um 8:37 Uhr

Benutzeravatar von Stephen Canon
Stefan Kanon

pmg ist genau richtig in Bezug auf die Kapselung; über das Verstecken der Funktion vor anderen Übersetzungseinheiten hinaus (oder besser gesagt, Weil davon), Funktionen machen static kann auch bei Vorhandensein von Compileroptimierungen Leistungsvorteile bringen.

Weil ein static Die Funktion kann nicht von irgendwo außerhalb der aktuellen Übersetzungseinheit aufgerufen werden (es sei denn, der Code nimmt einen Zeiger auf seine Adresse), der Compiler steuert alle Aufrufpunkte darin.

Dies bedeutet, dass es frei ist, eine nicht standardmäßige ABI zu verwenden, sie vollständig zu inlinen oder eine beliebige Anzahl anderer Optimierungen durchzuführen, die für eine Funktion mit externer Verknüpfung möglicherweise nicht möglich sind.

  • …es sei denn, die Adresse der Funktion ist belegt.

    – Café

    16. März 2011 um 0:06 Uhr

  • @caf Was meinst du damit, dass die Adresse der Funktion übernommen wird? Für mich ist die Vorstellung, dass Funktionen/Variablen Adressen haben oder zur Kompilierzeit Adressen zugewiesen werden, etwas verwirrend. Können Sie das bitte näher erläutern?

    – SayeedHussain

    2. August 2013 um 12:43 Uhr


  • @crypticcoder: Ihr Programm wird in den Speicher geladen, daher haben Funktionen auch einen Speicherort und die Adresse kann abgerufen werden. Mit einem Funktionszeiger könnten Sie jede davon aufrufen. Wenn Sie dies tun, wird die Liste der Optimierungen, die der Compiler durchführen kann, reduziert, da der Code an derselben Stelle intakt bleiben muss.

    Benutzer1454661

    2. August 2013 um 17:23 Uhr


  • @crypticcoder: Ich meine, dass ein Ausdruck einen Zeiger auf die Funktion auswertet und etwas anderes damit macht, als die Funktion sofort aufzurufen. Wenn ein Zeiger auf a static Funktion die aktuelle Übersetzungseinheit maskiert, dann könnte diese Funktion direkt von anderen Übersetzungseinheiten aufgerufen werden.

    – Café

    3. August 2013 um 0:02 Uhr

  • @caf Wenn die Adresse der Funktion verwendet wird, würde der Compiler dies erkennen und die in dieser Antwort erwähnten statischen Funktionsoptimierungen deaktivieren (z. B. unter Verwendung einer nicht standardmäßigen ABI)? Ich schätze, es müsste.

    – Sevko

    12. Juli 2018 um 15:52 Uhr

Das static Schlüsselwort in C wird in einer kompilierten Datei (.c im Gegensatz zu .h) verwendet, sodass die Funktion nur in dieser Datei existiert.

Wenn Sie eine Funktion erstellen, generiert der Compiler normalerweise Cruft, die der Linker verwenden kann, um einen Funktionsaufruf mit dieser Funktion zu verknüpfen. Wenn Sie das Schlüsselwort static verwenden, können andere Funktionen innerhalb derselben Datei diese Funktion aufrufen (weil dies ohne Rückgriff auf den Linker möglich ist), während der Linker keine Informationen hat, die anderen Dateien den Zugriff auf die Funktion ermöglichen.

  • 3Doub: Die Verwendung des Wortes „Cruft“ ist präziser, als Sie glauben. Im Zusammenhang mit der Frage ist “Cruft” das richtige Wort, das hier verwendet werden sollte.

    – Erik Aronesty

    20. November 2014 um 21:16 Uhr

  • @3Dublonen Ich stimme zu, dass es vereinfacht ist, aber ich denke, das macht es für Anfänger viel einfacher zu verstehen.

    – Ingo Bürk

    25. März 2015 um 7:47 Uhr

Benutzeravatar von mercury0114
Quecksilber0114

Wenn ich mir die obigen Beiträge ansehe, möchte ich eine klarere Antwort geben:

Angenommen, unsere main.c Datei sieht so aus:

#include "header.h"

int main(void) {
    FunctionInHeader();
}

Betrachten Sie nun drei Fälle:

  • Fall 1: Unsere header.h Datei sieht so aus:

     #include <stdio.h>
    
     static void FunctionInHeader();
    
     void FunctionInHeader() {
         printf("Calling function inside header\n");
     }
    

    Dann der folgende Befehl unter Linux:

     gcc main.c -o main
    

    wird gelingen! Das liegt daran, dass nach dem main.c Datei enthält die header.hdie Definition der statischen Funktion ist gleich main.c Datei (genauer gesagt in derselben Übersetzungseinheit) dorthin, wo sie aufgerufen wird.

    Wenn einer läuft ./mainwird die Ausgabe sein Calling function inside headerwas diese statische Funktion ausgeben sollte.

  • Fall 2: Unser Header header.h sieht aus wie das:

      static void FunctionInHeader();     
    

    und wir haben auch eine weitere Datei header.cdie so aussieht:

      #include <stdio.h>
      #include "header.h"
    
      void FunctionInHeader() {
          printf("Calling function inside header\n");
      }
    

    Dann der folgende Befehl

      gcc main.c header.c -o main
    

    wird einen Fehler geben. In diesem Fall main.c enthält nur die Deklaration der statischen Funktion, aber die Definition wird in einer anderen Übersetzungseinheit belassen und die static Schlüsselwort verhindert, dass der Code eine zu verknüpfende Funktion definiert

  • Fall 3:

    Ähnlich wie Fall 2, nur dass jetzt unser Header header.h Datei ist:

      void FunctionInHeader(); // keyword static removed
    

    Dann wird derselbe Befehl wie in Fall 2 ausgeführt und weiter ausgeführt ./main wird das erwartete Ergebnis liefern. Hier die FunctionInHeader Definition befindet sich in einer anderen Übersetzungseinheit, aber der Code, der sie definiert, kann verknüpft werden.

Also zum Schluss:

static keyword prevents the code defining a function to be linked,
when that function is defined in another translation unit than where it is called.

C-Programmierer verwenden das statische Attribut, um Variablen- und Funktionsdeklarationen innerhalb von Modulen zu verbergen, ähnlich wie Sie öffentliche und private Deklarationen in Java und C++ verwenden würden. C-Quelldateien spielen die Rolle von Modulen. Jede mit dem statischen Attribut deklarierte globale Variable oder Funktion ist für dieses Modul privat. Ebenso ist jede globale Variable oder Funktion, die ohne das statische Attribut deklariert wurde, öffentlich und kann von jedem anderen Modul aufgerufen werden. Es gehört zur guten Programmierpraxis, Ihre Variablen und Funktionen nach Möglichkeit mit dem statischen Attribut zu schützen.

Benutzeravatar von human.js
human.js

Die Antwort von pmg ist sehr überzeugend. Wenn Sie wissen möchten, wie statische Deklarationen auf Objektebene funktionieren, könnten die folgenden Informationen für Sie interessant sein. Ich habe dasselbe von pmg geschriebene Programm wiederverwendet und es in eine .so(shared object)-Datei kompiliert

Der folgende Inhalt ist nach dem Ablegen der .so-Datei in etwas für Menschen lesbar

0000000000000675 f1: Adresse der Funktion f1

000000000000068c f2: Adresse der Funktion f2(staticc).

Beachten Sie den Unterschied in der Funktionsadresse, es bedeutet etwas. Für eine Funktion, die mit einer anderen Adresse deklariert ist, kann dies sehr gut bedeuten, dass f2 sehr weit entfernt oder in einem anderen Segment der Objektdatei lebt.

Linker verwenden etwas namens PLT (Procedure Linkage Table) und GOT (Global Offsets Table), um Symbole zu verstehen, auf die sie Zugriff haben.

Stellen Sie sich vorerst vor, dass GOT und PLT alle Adressen auf magische Weise binden und ein dynamischer Abschnitt Informationen zu all diesen Funktionen enthält, die für den Linker sichtbar sind.

Nach dem Sichern des dynamischen Abschnitts der .so-Datei erhalten wir eine Reihe von Einträgen, die uns aber nur interessieren f1 und f2 Funktion.

Der dynamische Abschnitt enthält nur den Eintrag für f1 Funktion unter Adresse 0000000000000675 und nicht für f2 !

Num: Wert Größe Typ Bind Vis Ndx Name

 9: 0000000000000675    23 FUNC    GLOBAL DEFAULT   11 f1

Und das ist es !. Daraus ist klar, dass der Linker beim Auffinden der nicht erfolgreich sein wird f2 funktionieren, da sie nicht im dynamischen Abschnitt der .so-Datei enthalten ist.

Benutzeravatar von Amna Salman
Amna Salmann

Wenn der Zugriff auf einige Funktionen eingeschränkt werden muss, verwenden wir das Schlüsselwort static beim Definieren und Deklarieren einer Funktion.

            /* file ab.c */ 
static void function1(void) 
{ 
  puts("function1 called"); 
} 
And store the following code in another file ab1.c

/* file ab1.c  */ 
int main(void) 
{ 
 function1();  
  getchar(); 
  return 0;   
} 
/* in this code, we'll get a "Undefined reference to function1".Because function 1 is declared static in file ab.c and can't be used in ab1.c */

  • Diese Antwort ist nicht sehr hilfreich.

    – Fischblog

    4. Juni 2020 um 12:21 Uhr

1425310cookie-checkstatische Funktion in C

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

Privacy policy