includes
-
In welcher Sprache sind eigentlich die includes wie stdlib
oder iostream geschrieben ?
Kann man die Fuktionen
wie printf(...) oder auch class String irgendwo im Quelltext nachlesen ?
Wieviele der Kerfunktionen (getc, putc usw..) muß zwingend in Assembler
definiert sein ?
-
Man kann das alles in C oder C++ schreiben, ohne auf andere Sprachen zurückzuweichen.
-
Hi,
das nennt sich zusammengefasst: 'Die C/C++ Laufzeitbibliotheken' und wird normalerweise immer vom Compilerbauer mitgeliefert.
Normalerweise sind sie vorkompiliert bis auf die entsprechenden Deklarationen in den Headern.
Ob die Definitionen der Funktionen auch als Quelltext verfügbar sind ist dann von Fall zu Fall unterschiedlich.Klarerweise ist es so bei dem OpenSource-GCC und auch MS Visual C++ liefert die Runtime als Quelltext mit, damit man sich beim Debuggen leichter tut.
Manche elementere Funktionen wie z.B. malloc brauchen auch gar nicht zwingend vorliegen, sondern sind manchmal schon im Compiler eingebaut.
-
Danke. Aber daß man *alle* includes in C/C++ machen kann, kann ich mir
nicht ganz vorstellen - zumindest die primitivsten Sachen wie
"Zeichen lesen", "Zeichen schreiben", "Speicher belegen" etc.. muüssen
doch in Assembler vorliegen, weil C/C++ keine eingebauten Befehle dafür hat, einen
System call für "Zeichen schreiben" auszulösen.Aber wo konkret muß man denn nachsehen, wenn man den Quellcode von z.B.
printf oder class String nachsehen will ?
-
Nein, dafür gibts unter Windows die WinAPI.
-
Bei manchen Compilern ist der Quelltext der Laufzeitbibliothek dabei. Welchen hast du denn?
-
B. Dynbreth schrieb:
Danke. Aber daß man *alle* includes in C/C++ machen kann, kann ich mir
nicht ganz vorstellen - zumindest die primitivsten Sachen wie
"Zeichen lesen", "Zeichen schreiben", "Speicher belegen" etc.. muüssen
doch in Assembler vorliegen, weil C/C++ keine eingebauten Befehle dafür hat, einen
System call für "Zeichen schreiben" auszulösen.Aber wo konkret muß man denn nachsehen, wenn man den Quellcode von z.B.
printf oder class String nachsehen will ?Für diese Sachen gibt es eine API des Betriebssystems. Bei UNIX ist diese API durch C Funktionen gekapselt. Diese C Funktionen werden dann verwendet, um die Laufzeitumgebung zu programmieren. Die Kapselung und die Laufzeitumgebung befindet sich unter UNIX zusammen mit vielen anderen Funktionen in der Regel in der libc.
-
Aha. Gut, printf ist z.B. eine C-Funktion, die in C codiert werden kann und
auf "primitive" Systemaufrufe wie "Zeichen ausgeben" aufruft. Aber wie
geht das in C ? Meines Wissens hat C keinen eingebauten Befehl für
Primitive und so etwas wie "syscall(int_16h)" gibt des doch in C auch nicht.
Wie also geht das zusammen ? Wird der C-Code der prinft-Funktion gelinkt
gegen eine in Assembler geschriebene Bibliothek, die die Systemaufrufe in
Assembler-Programm "wrapt", die dann von C aus aufgerufen werden oder wie ??
-
Um solch eine Betriebssystem-Funktion aufrufen zu können brauch man einfach nur einen Zeiger auf die Funktion.
-
B. Dynbreth schrieb:
Aha. Gut, printf ist z.B. eine C-Funktion, die in C codiert werden kann und
auf "primitive" Systemaufrufe wie "Zeichen ausgeben" aufruft. Aber wie
geht das in C ? Meines Wissens hat C keinen eingebauten Befehl für
Primitive und so etwas wie "syscall(int_16h)" gibt des doch in C auch nicht.
Wie also geht das zusammen ? Wird der C-Code der prinft-Funktion gelinkt
gegen eine in Assembler geschriebene Bibliothek, die die Systemaufrufe in
Assembler-Programm "wrapt", die dann von C aus aufgerufen werden oder wie ??Man kann in C Assemblercode embedden. Zum Beispiel verwendet printf Funktionen, um Zeichen raus zu schreiben. Diese werden Systemaufrufe genannt und werden durch Makros der folgenden Art definiert:
#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ type name(type1 arg1,type2 arg2,type3 arg3) \ { \ long __res; \ __asm__ volatile ("int $0x80" \ : "=a" (__res) \ : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \ "d" ((long)(arg3))); \ __syscall_return(type,__res); \ }
Dadurch wird ein Systemaufruf mit drei Parametern definiert. Mit
_syscall3(ssize_t,write,int,fd,const void *,buf,size_t,count);
wird zum Beispiel write definiert, zum Schreiben auf einen Filedeskriptor.
Das expandiert zu folgender C Funktion mit eingebettetem Assembler:
ssize_t write(int fd, const void * buf, size_t count) { long __res; __asm__ volatile ("int $0x80" : "=a" (__res) : "0" (__NR_##write),"b" ((long)(fd)),"c" ((long)(buf)), "d" ((long)(count))); do { if ((unsigned long)(__res) >= (unsigned long)(-125)) { errno = -(__res); res = -1; } return (ssize_t) (__res); } while (0) }
Der letzte Teil der Funktion kommt daher, das __syscall_return noch ein anderes Makro ist.
Insgesamt ruft also die printf Funktion den Systemaufruf auf. Dieser macht einen Interrupt und nimmt das Ergebnis entgegen. Dann wird eventuell errno gesetzt und das Ergebnis der Funktion an printf zurückgegeben.
-
Unter Windows ist die Schnittstelle zum Betriebssystem die Winapi, diese ist nicht irgendwie sprachabhängig, du musst die Funktionen nur der geforderten Aufrufkonvention entsprechend aufrufen und die gewünschten Parameter übergeben, diese haben vorgeschriebene Größen.
Möchtest du die Winapi zB. mit C verwenden, so kannst du dir bei Microsoft das "Platform SDK" herunterladen, welches Funktionsprototypen für sämtliche winapi-funktionen enthält und typedefs für die erforderlichen typen. Windows lädt beim starten von Anwendungen einige dlls mit, diese werden in der Registry angegeben, welche die winapi funktionen enthalten. Dein Compiler linkt diese statisch zu deinem Programm hinzu, wodurch du einfach die Funktionen ihrem Namen entsprechend aufrufen kannst ohne sie vorher aus der dll laden zu müssen (das geschieht beim statischen linken im hintergrund).Das System wie Windows aufgebaut ist, ist etwas komplexer, jedenfalls ist die Winapi in C geschrieben und verwendet intern eine Schnittstelle zum Betriebssystem . Wenn du dich für genauere Details interressierst, wären Bücher wie Undocumented WindowsNT interressant.
Das war der Teil zu Windows, unter Linux nennt sich die Schnittstelle zum Betriebssystem POSIX, das ist ein Standard, so wie ISO-C99, nach welchem die Schnittstelle erschaffen wurde (Windows untersützt neben der Winapi auch POSIX, allerdings nur einen sehr alten standard, der fast nichts kann, daher verwendet ihn auch niemand), die C Bibliothek ruft hier einfach die entsprechenden Funktionen auf.
Sehr viele Funktionen in den Betriebssystemschnittstellen sind denen aus der Standardbibliothek von C sehr ähnlich, daher haben es die Entwickler der C Standardbibliothek nicht unmenschlich schwer, sondern können die Standardbibliothek einfach in C schreiben und die entsprechenden Betriebssystemfunktionen aufrufen.
Und das Betriebssystem selbst hat auch nur auf der untersten Ebene Assembler Code, der Rest ist auch da in ner höheren Sprache (derzeit sind alle großen Betriebssysteme in C/C++) geschrieben.
-
diese werden in der Registry angegeben
glaube das ist falsch.
-
Habe recht lange geschrieben und Ponto hat währenddessen sein Posting abgesetzt.
Ponto dein Beispiel stammt wohl aus einem *NIX.
In der printf Funktion von Microsoft's Visual C++.NET findet man nicht eine einzige Zeile Assembler Code, es werden dort Hilfsfunktionen zur Ausgabe verwendet, welche selbst wiederum die Betriebssystemschnittstelle benutzen.
-
falsch! schrieb:
diese werden in der Registry angegeben
glaube das ist falsch.
Habe eben nachgesehen und du hast recht, hatte da etwas falsch in Erinnerung, denn es gibt einen Registry Wert in welchen man dlls eintragen kann die jedes Programm beim starten mitlädt, jedoch nicht die system dlls.
Denn diese liegen in einem Adressraum auf welches jeder Prozess lesezugriff hat (beim Schreibzugriff wird eine Kopie im eigenen Raum für den Prozess erstellt), so spart man Speicher.
-
User-- schrieb:
Habe recht lange geschrieben und Ponto hat währenddessen sein Posting abgesetzt.
Ponto dein Beispiel stammt wohl aus einem *NIX.
In der printf Funktion von Microsoft's Visual C++.NET findet man nicht eine einzige Zeile Assembler Code, es werden dort Hilfsfunktionen zur Ausgabe verwendet, welche selbst wiederum die Betriebssystemschnittstelle benutzen.Klar, ich spreche nur über UNIX. Und auch dort ruft printf wahrscheinlich nicht direkt write auf. Aber irgendwann muss write mit dem Deskriptor 1 aufgerufen werden.
-
nein mit dem Deskriptor stdout
-
nein schrieb:
nein mit dem Deskriptor stdout
stdout ist ein FILE * und kein Deskriptor. Und auf welchem Unix System ist der entsprechende Stream nicht mit Deskriptor 1 verbunden?
-
ab Linux 9.3 ist stdout standartmässig mit deskriptor 1 verbunden.
-
libc-user schrieb:
ab Linux 9.3 ist stdout standartmässig mit deskriptor 1 verbunden.
Der ist gut.
-
ponto:
Dein Code-Beispiel ist schön illustrativ - jetzt kann ich mir
in etwa vorstellen, wie das programmtechnisch realisiert ist. thx.