bibliotheken



  • Wo kann ich sehen was in den einzelnen Bibliotheken steht. Denn ich wollte mir mal den Quellcode von

    <cassert>
    

    anschauen, finde aber nichts im Internet.

    Gruß



  • Eine Übersicht über die Standardbibliothek mit Erklärungen und Beispielen: http://en.cppreference.com/w/ Nach Headern geordnet: http://en.cppreference.com/w/cpp/header
    Oder halt den Standard bemühen: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3797.pdf


  • Mod

    cassert ist keine Bibliothek, sondern eine Headerdatei.

    Da vom Sprachstandard nur definiert ist, welche Funktionalität zur Verfügung stehen muss, aber nicht genau wie, wirst du auch im Internet keine Vorgabeimplementierung finden. Da der Header aber auf deinem System irgendwo zur Verfügung stehen muss, kannst du ihn dir dort natürlich auch direkt angucken. Oder, wenn du keine Ahnung hast, wo du die Dateien findest, schau dir die Ausgabe des Präprozessors an (bei cassert wird jedoch nichts übrig bleiben, da dort nur Makros definiert werden). Bei den Headern der C-Bibliothek wird dies nicht sehr spannend sein, bloß eine lange Liste an Funktionsdeklarationen. Spannender wird die STL, da für Templates der Code tatsächlich im Header stehen muss. Aufgrund der Namenskonventionen ist solcher Code jedoch einigermaßen unlesbar 😞 .
    Die eigentliche Implementierung der Standardbibliothek (also das, was man eigentlich Bibliothek nennt, nicht die Header), liegt auf deinem System schon in übersetzter Fassung vor. Wenn deine Implementierung nicht Open Source ist, dann kannst du auch nicht in den Quellcode gucken. Wenn es Open Source ist, dann kannst du auch den Quellcode irgendwo bekommen, zum Beispiel tatsächlich aus dem Internet. Beispielsweise GNU C=Bibliothek:
    http://www.gnu.org/software/libc/
    oder C++:
    http://gcc.gnu.org/libstdc++/

    Beispiel cassert:

    // Ganz viel Copyright-Zeug, das ich hier mal weglasse
    #pragma GCC system_header
    
    #include <assert.h>
    

    Da haben wir viel gelernt, oder? 😃



  • Ups, dachte das wär eine Bibliothek :p
    Weil in dem Buch "Der C++ Programmierer" steht:

    Werfen sie einen Blick in die Datei assert.h, um die Wirkungsweise des Makros zu studieren!

    Und das wollte ich halt tun, habe aber halt keine Ahnung wo diese Datei zu finden ist :s



  • Ups, dachte das wär eine Bibliothek :p
    Weil in dem Buch "Der C++ Programmierer" steht:

    Werfen sie einen Blick in die Datei assert.h, um die Wirkungsweise des Makros zu studieren!

    Und das wollte ich halt tun, habe aber halt keine Ahnung wo diese Datei zu finden ist :s

    SeppJ schrieb:

    Beispiel cassert:

    // Ganz viel Copyright-Zeug, das ich hier mal weglasse
    #pragma GCC system_header
    
    #include <assert.h>	
    Da haben wir viel gelernt, oder? :D
    

    Hammer 🙂


  • Mod

    Skeptar schrieb:

    Werfen sie einen Blick in die Datei assert.h, um die Wirkungsweise des Makros zu studieren!

    Ok, ich bin mal nicht so. Hier assert.h von einem älteren GCC (wird sich aber nicht verändert haben):

    /* Copyright (C) 1991,1992,1994-2001,2003,2004,2007
       Free Software Foundation, Inc.
       This file is part of the GNU C Library.
    
       The GNU C Library is free software; you can redistribute it and/or
       modify it under the terms of the GNU Lesser General Public
       License as published by the Free Software Foundation; either
       version 2.1 of the License, or (at your option) any later version.
    
       The GNU C Library is distributed in the hope that it will be useful,
       but WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       Lesser General Public License for more details.
    
       You should have received a copy of the GNU Lesser General Public
       License along with the GNU C Library; if not, write to the Free
       Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
       02111-1307 USA.  */
    
    /*
     *	ISO C99 Standard: 7.2 Diagnostics	<assert.h>
     */
    
    #ifdef	_ASSERT_H
    
    # undef	_ASSERT_H
    # undef	assert
    # undef __ASSERT_VOID_CAST
    
    # ifdef	__USE_GNU
    #  undef assert_perror
    # endif
    
    #endif /* assert.h	*/
    
    #define	_ASSERT_H	1
    #include <features.h>
    
    #if defined __cplusplus && __GNUC_PREREQ (2,95)
    # define __ASSERT_VOID_CAST static_cast<void>
    #else
    # define __ASSERT_VOID_CAST (void)
    #endif
    
    /* void assert (int expression);
    
       If NDEBUG is defined, do nothing.
       If not, and EXPRESSION is zero, print an error message and abort.  */
    
    #ifdef	NDEBUG
    
    # define assert(expr)		(__ASSERT_VOID_CAST (0))
    
    /* void assert_perror (int errnum);
    
       If NDEBUG is defined, do nothing.  If not, and ERRNUM is not zero, print an
       error message with the error text for ERRNUM and abort.
       (This is a GNU extension.) */
    
    # ifdef	__USE_GNU
    #  define assert_perror(errnum)	(__ASSERT_VOID_CAST (0))
    # endif
    
    #else /* Not NDEBUG.  */
    
    #ifndef _ASSERT_H_DECLS
    #define _ASSERT_H_DECLS
    __BEGIN_DECLS
    
    /* This prints an "Assertion failed" message and aborts.  */
    extern void __assert_fail (__const char *__assertion, __const char *__file,
    			   unsigned int __line, __const char *__function)
         __THROW __attribute__ ((__noreturn__));
    
    /* Likewise, but prints the error text for ERRNUM.  */
    extern void __assert_perror_fail (int __errnum, __const char *__file,
    				  unsigned int __line,
    				  __const char *__function)
         __THROW __attribute__ ((__noreturn__));
    
    /* The following is not at all used here but needed for standard
       compliance.  */
    extern void __assert (const char *__assertion, const char *__file, int __line)
         __THROW __attribute__ ((__noreturn__));
    
    __END_DECLS
    #endif /* Not _ASSERT_H_DECLS */
    
    # define assert(expr)							\
      ((expr)								\
       ? __ASSERT_VOID_CAST (0)						\
       : __assert_fail (__STRING(expr), __FILE__, __LINE__, __ASSERT_FUNCTION))
    
    # ifdef	__USE_GNU
    #  define assert_perror(errnum)						\
      (!(errnum)								\
       ? __ASSERT_VOID_CAST (0)						\
       : __assert_perror_fail ((errnum), __FILE__, __LINE__, __ASSERT_FUNCTION))
    # endif
    
    /* Version 2.4 and later of GCC define a magical variable `__PRETTY_FUNCTION__'
       which contains the name of the function currently being defined.
       This is broken in G++ before version 2.6.
       C9x has a similar variable called __func__, but prefer the GCC one since
       it demangles C++ function names.  */
    # if defined __cplusplus ? __GNUC_PREREQ (2, 6) : __GNUC_PREREQ (2, 4)
    #   define __ASSERT_FUNCTION	__PRETTY_FUNCTION__
    # else
    #  if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
    #   define __ASSERT_FUNCTION	__func__
    #  else
    #   define __ASSERT_FUNCTION	((__const char *) 0)
    #  endif
    # endif
    
    #endif /* NDEBUG.  */
    

    Wie schon gesagt: Größtenteils unlesbar 🙂

    Wenn man sich durchkämpft, dann findet man die entscheidenden Teile:

    #ifdef  NDEBUG
    
    # define assert(expr)       (__ASSERT_VOID_CAST (0))
    

    Der Sprachstandard verlangt, dass im Fall von NDEBUG das Makro assert zu ((void)0) ausgewertet werden soll. Das wird hier gemacht. Und der andere, interessante, Fall geschieht hier:

    #else /* Not NDEBUG.  */
    
    #ifndef _ASSERT_H_DECLS
    #define _ASSERT_H_DECLS
    __BEGIN_DECLS
    
    /* This prints an "Assertion failed" message and aborts.  */
    extern void __assert_fail (__const char *__assertion, __const char *__file,
                   unsigned int __line, __const char *__function)
         __THROW __attribute__ ((__noreturn__));
    
    /* Likewise, but prints the error text for ERRNUM.  */
    extern void __assert_perror_fail (int __errnum, __const char *__file,
                      unsigned int __line,
                      __const char *__function)
         __THROW __attribute__ ((__noreturn__));
    
    /* The following is not at all used here but needed for standard
       compliance.  */
    extern void __assert (const char *__assertion, const char *__file, int __line)
         __THROW __attribute__ ((__noreturn__));
    
    __END_DECLS
    #endif /* Not _ASSERT_H_DECLS */
    
    # define assert(expr)                           \
      ((expr)                               \
       ? __ASSERT_VOID_CAST (0)                     \
       : __assert_fail (__STRING(expr), __FILE__, __LINE__, __ASSERT_FUNCTION))
    
    // ...
    
    #endif /* NDEBUG.  */
    

    Das ist schon deutlich komplizierter. Bis Zeile 25 werden ein paar Funktionen deklariert, deren Code wir nicht kennen, aber dem Namen und Beschreibung nach geben sie eine Fehlermeldung aus, eben genau das, was assert im Fehlerfall machen soll. Das eigentlich assert-Makro folgt danach. Das ist wahrscheinlich der Teil, den du studieren sollst, daher sage ich dazu nichts.



  • Du hast zu 120% recht das ich davon kaum etwas verstehen :p
    Aber trodzdem danke für den aufwand.


  • Mod

    Skeptar schrieb:

    Du hast zu 120% recht das ich davon kaum etwas verstehen :p
    Aber trodzdem danke für den aufwand.

    Es ist vielleicht einfacher zu verstehen, wenn du dran denkst, dass fast alles hier Makros sind. Außerdem kannst du im Kopf alle Unterstriche wegdenken, die sind bloß da, um Namenskollisionen zu verhindern. Danach ist das wie das Lesen von typischen Präprozessorcode, der aber eben nicht viel mit C oder C++ gemeinsam hat. Zum Lesen musst du dann fit sein und verstehen, was ifdef, define & Co. machen. Dann machst du das im Kopf nach. Beispielsweise der Fall, dass NDEBUG definiert ist (also wenn assert einfach übersprungen werden soll):

    #if defined __cplusplus && __GNUC_PREREQ (2,95)
    # define __ASSERT_VOID_CAST static_cast<void>
    #else
    # define __ASSERT_VOID_CAST (void)
    #endif
    
    /* void assert (int expression);
    
       If NDEBUG is defined, do nothing.
       If not, and EXPRESSION is zero, print an error message and abort.  */
    
    #ifdef  NDEBUG
    
    # define assert(expr)       (__ASSERT_VOID_CAST (0))
    

    Zeile 1 prüft, ob wir C++ machen. Falls ja, wird in Zeile 2 __ASSERT_VOID_CAST als ein C++-static_cast zu void definiert, falls nein (Zeile 3), dann machen wir wohl C und in Zeile 4 wird __ASSERT_VOID_CAST als ein C-Cast zu void definiert. Zeile 5 beendet den if-Block. Dann kommt ein Kommentar, der nochmal erklärt, was assert überhaupt macht. Dann wird in Zeile 12 geprüft, ob NDEBUG definiert ist. Falls ja, wird assert als (__ASSERT_VOID_CAST (0)) definiert. Das __ASSERT_VOID_CAST ist dabei das Makro für den Cast von oben*. Es wird also 0 zu void gecastet, was in beiden Sprachen einfach gar nichts macht.
    Danach geht's weiter in der Art und Weise. Man muss eben Präprozessor lesen können.

    *: Hier ist es nicht wichtig, aber man sollte noch erwähnen, dass der Präprozessor lazy evaluation benutzt:

    #define FOO 5
    #define BAR FOO
    
    #undef FOO
    #define FOO 6
    
    BAR  // 6, nicht 5
    

Anmelden zum Antworten