Warum haben einige Funktionen in C einen Unterstrich als Präfix?

Lesezeit: 5 Minuten

Ich habe vor kurzem angefangen, Networking in C zu lernen, und ich habe einige Funktionen gesehen, die mit einem Unterstrich beginnen – wie _function() – was bedeutet das genau? Das habe ich auch gesehen:

 struct sockaddr_in  {  

__SOCKADDR_COMMON (sin_);  

 in_port_t sin_port;    

 struct in_addr sin_addr;    

 unsigned char sin_zero[sizeof (struct sockaddr) - 

 __SOCKADDR_COMMON_SIZE -  

sizeof (in_port_t) -         

sizeof (struct in_addr)];  

};

Was bedeutet dieser Teil des Codes:

__SOCKADDR_COMMON (sin_);

unsigned char sin_zero[sizeof (struct sockaddr) - 

 __SOCKADDR_COMMON_SIZE -  

sizeof (in_port_t) -         

sizeof (struct in_addr)];

  • Siehe auch Was bedeutet doppelter Unterstrich (__const) bedeuten in C? die den C-Standard zum Thema Namen zitiert, die mit Unterstrichen beginnen.

    – Jonathan Leffler

    21. September 2016 um 20:51 Uhr


Benutzeravatar von Dietrich Epp
Dietrich Ep

Das Unterstrich-Präfix ist für Funktionen und Typen reserviert, die vom Compiler und der Standardbibliothek verwendet werden. Die Standardbibliothek kann diese Namen frei verwenden, da sie niemals mit korrekten Benutzerprogrammen in Konflikt geraten.

Die Kehrseite dazu ist, dass Sie keine Namen definieren dürfen, die mit einem Unterstrich beginnen.

Nun, das ist der Kern der Regel. Die eigentliche Regel lautet:

  • Sie können im globalen Geltungsbereich keine Bezeichner definieren, deren Namen mit einem Unterstrich beginnen, da diese mit verborgenen (privaten) Bibliotheksdefinitionen in Konflikt geraten können. Das ist also in Ihrem Code ungültig:

    #ifndef _my_header_h_
    #define _my_header_h_ // wrong
    int _x; // wrong
    float _my_function(void); // wrong
    #endif
    

    Aber das gilt:

    #ifndef my_header_h
    #define my_header_h // ok
    int x; // ok
    float my_function(void) { // ok
        int _x = 3; // ok in function
    }
    struct my_struct {
        int _x; // ok inside structure
    };
    #endif
    
  • Sie können in keinem Gültigkeitsbereich Bezeichner definieren, deren Namen mit zwei Unterstrichen oder einem Unterstrich gefolgt von einem Großbuchstaben beginnen. Das ist also ungültig:

    struct my_struct {
        int _Field; // Wrong!
        int __field; // Wrong!
    };
    void my_function(void) {
        int _X; // Wrong!
        int __y; // Wrong!
    }
    

    Aber das ist in Ordnung:

    struct my_struct {
        int _field; // okay
    };
    void my_function(void) {
        int _x; // okay
    }
    

Es gibt noch ein paar weitere Regeln, nur um die Dinge komplizierter zu machen, aber die oben genannten werden am häufigsten verletzt und sind am einfachsten zu merken.

  • @CraigEstey __x und _X können Makros sein. Dies ist jedoch eine pgmr-Entscheidung in Bezug auf ein solches Risiko. 99,44 % aller dieser Namen werden niemals in Konflikt geraten Und viel Glück beim Finden des Problems, wenn es einen Konflikt gibt. Wenn man bedenkt, wie einfach es ist, Fehler in den Code zu einbauen, warum um alles in der Welt sollten Sie das tun? je tun Sie irgendetwas, von dem Sie wissen, dass es unmöglich zu findende Fehler einführen könnte?

    – Andreas Henle

    21. September 2016 um 20:31 Uhr

  • @CraigEstey: Dann hast du Glück. Ich programmiere erst seit etwa 33 Jahren in C und bin auf einige unangenehme Probleme gestoßen, weil interner Code Namen verwendet, die mit Unterstrichen beginnen und mit einer Systemfunktion mit demselben Namen in Konflikt stehen. Die Dinge gehen schief, wenn Ihr Code definiert int _bind(int x, char y); und das System definiert und ruft auf char *_bind(void *p, char *a, int f); oder etwas Ähnliches – und der Systembibliothekscode ruft schließlich Ihre auf _bind() statt der beabsichtigten. Das war vor ein paar Jahren (eigentlich einem anderen Jahrtausend), aber ich erinnere mich an diesen und einige ähnliche Fälle.

    – Jonathan Leffler

    21. September 2016 um 20:56 Uhr

  • @CraigEstey Das “_” ist eine POSIX-Bibliothekskonvention Lesen Sie bitte 7.1.3 Reservierte Kennungen von der C-Standard: Alle Bezeichner, die mit einem Unterstrich und entweder einem Großbuchstaben oder einem anderen Unterstrich beginnen, sind immer für jegliche Verwendung reserviert. und Alle Bezeichner, die mit einem Unterstrich beginnen, sind immer für die Verwendung als Bezeichner mit Dateibereich sowohl im normalen als auch im Tag-Namensraum reserviert. Logischerweise ist Ihr Argument das gleiche wie “Ich bin mit Haien geschwommen, während ich mit Blut bedeckt war, und wurde nicht gefressen.” 35 Jahre sagst du?

    – Andreas Henle

    21. September 2016 um 21:02 Uhr

  • @CraigEstey: deswegen habe ich „ein weiteres Jahrtausend“ erwähnt – die Probleme sind heutzutage oft anders, aber die Namenswahl kann immer noch Probleme bereiten. Das ist einer von wenigen (weniger als einem halben Dutzend, glaube ich) Fällen von Eingriffen in Namen mit führendem Unterstrich. (Ich füge hinzu, die lokale Verwendung von _bind() als Name war nicht meine Wahl, und er verursachte kein Problem, bis er auf eine neue Plattform portiert wurde.) Ich hatte mehr Probleme mit _t Suffixe für Typen, die POSIX reserviert. Theoretisch müssen Sie die POSIX-Funktionalität aktiv aktivieren – Pace -std=gnu11 das macht es automatisch. […continued…]

    – Jonathan Leffler

    21. September 2016 um 21:34 Uhr

  • […continuation…] Die POSIX-Regeln sind da, damit Sie kein Comeback haben, wenn Sie sie verletzen und es wehtut. Das gilt weitgehend auch für die C-Regeln. Sie leiten auch die Entwickler von Systemen an – wenn sie die Regeln befolgen, werden sie ihren Benutzern nicht schaden, wenn diese Benutzer sich auch an die Regeln halten. Das Knifflige daran ist, dass Neulinge auf Systemheader schauen und denken „Oh, so muss ich meine Header auch schreiben“ und sofort alle Regeln brechen, die aufgestellt wurden, um zu verhindern, dass sich Benutzer und Systemanbieter gegenseitig verletzen. Letztlich ist das ein Erziehungsproblem. SO kann helfen.

    – Jonathan Leffler

    21. September 2016 um 21:36 Uhr

Führende Unterstriche zeigen normalerweise eines von drei Dingen an:

  1. Die Definition ist nicht Teil des C-Standards, also nicht portierbar
  2. Die Definition ist intern für eine Bibliothek oder einen Compiler und sollte nicht von außen verwendet werden
  3. Die Definition sollte nicht auf die leichte Schulter genommen werden, da sie ein gewisses Risiko oder eine notwendige Konfiguration impliziert, die zusätzliche Kenntnisse erfordert.

In diesem Fall, __SOCKADDR_COMMON ist (2): eine interne Definition, Teil der struct sockaddr_in Typ, auf den Sie normalerweise vom Userland aus zugreifen.

1437400cookie-checkWarum haben einige Funktionen in C einen Unterstrich als Präfix?

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

Privacy policy