Nur mal theoretisch:
Kann man die Adresse von Sprungmarken auslesen, um sie in einer
Sprungtabelle zu speichern? Und natürlich wird das passende Gegenstück
benötigt, ein indirekter Jump-Befehl, der eine Adresse in einer
Sprungtabelle ansteuern kann (Goto will ich das nicht nennen, ich
fürchte Schläge ;-) )
Das ist ja nur theoretisch, eine Art "on <Ausdruck> goto <Sprungmarke>".
Ich vermute, ohne Asm-Einbindung ist das in C nicht realisierbar, oder?
Es ist wirklich nur theoretisch. Niemand will eine Mauer bauen :D
Wer doch den Zeigefinger heben muss, weil er nicht anders kann, bedenke:
switch ist auch nicht mehr als ein ausdruckgesteuertes GOTO
Frotho schrieb:> Nur mal theoretisch:>> Kann man die Adresse von Sprungmarken auslesen
Ja aus dem MAP File welches vom Linker erzeugt wird.
, um sie in einer
> Sprungtabelle zu speichern? Und natürlich wird das passende Gegenstück> benötigt, ein indirekter Jump-Befehl, der eine Adresse in einer> Sprungtabelle ansteuern kann (Goto will ich das nicht nennen, ich> fürchte Schläge ;-) )
Warum willst du unbedingt zu bestimmten Adressen springen?
Wenn du dynamisch "springen" willst, nimm Funktionspointer.
Die kannst du in Arrays und Structs verwalten wie du lustig bist.
> Das ist ja nur theoretisch, eine Art "on <Ausdruck> goto <Sprungmarke>".> Ich vermute, ohne Asm-Einbindung ist das in C nicht realisierbar, oder?
Du kannst auch in C direkt zu jeder Adresse springen. Nimmt man z.B. für
Sprünge in den Bootloader.
>> Es ist wirklich nur theoretisch. Niemand will eine Mauer bauen :D
Cyblord -. schrieb:> Warum willst du unbedingt
Will ich doch gar nicht
Frotho schrieb:> Niemand will eine Mauer bauen :D> Wenn du dynamisch "springen" willst, nimm Funktionspointer.
Funktionspointer sind doch Pointer auf Funktionen. Das ist ganz was
anderes als ein Label innerhalb einer Funktion.
Wer immer nur mit der Herde blökt "goto ist pfui", wird auch immer nur
in seinem (Denk)Gatter bleiben. Jedem das seine. Ein sinnvoller Einsatz
von Goto (außer in absoluten Ausnahmefällen wie bei Fehlern) fällt mir
gerade auch nicht ein (nicht mal in BASIC). Pfui ist es deswegen noch
lange nicht.
Gosub habe ich z.B. gerne verwendet. Für Routinen, die an mehreren
Stellen innerhalb einer Funktion dasselbe tun, war Gosub ideal, um die
Anzahl von Sonderfunktionen (Funtions-Unterfunktionen) zu reduzieren.
Außerdem, wenn die Routine viele Parameter hat, die lokal innerhalb
der Funktion zur Verfügung stehen, warum soll man die an eine
Unterfunktion übergeben müssen, wenn es auch einfacher geht? Hat ja auch
was mit Übersicht in komplexen Programmen zu tun. Nur mal so zur
Theorie. Und daraus entsteht eben KEIN Spaghetticode (manche Leute
kriegen Spaghetticode übrigens auch mit üblichen Mitteln hin...).
Frotho schrieb:>> Wenn du dynamisch "springen" willst, nimm Funktionspointer.> Funktionspointer sind doch Pointer auf Funktionen. Das ist ganz was> anderes als ein Label innerhalb einer Funktion.
Dein Anspruch war, Sprunkmarken in einer Tabelle zu verwalten. Das geht
mit Funktionspointern sehr gut. Dazu brauchts kein Goto.
Und warum will man INNERHALB einer Funktion springen? Dafür gibts, wie
du schon gemerkt hast, Switch.
>> Wer immer nur mit der Herde blökt "goto ist pfui", wird auch immer nur> in seinem (Denk)Gatter bleiben. Jedem das seine. Ein sinnvoller Einsatz> von Goto (außer in absoluten Ausnahmefällen wie bei Fehlern) fällt mir> gerade auch nicht ein (nicht mal in BASIC). Pfui ist es deswegen noch> lange nicht.
Du willst anscheinend nur wegen Goto rumpöbeln. Niemand hat hier Goto
als Pfui bezeichnet. Dass man es nicht einfach hernehmen sollte um Wild
im Programm zu springen ist heute fast jedem klar. Nur dein Szenario,
nämlich Sprungmarken in Tabellen zu halten erfüllt es auch nicht.
> Will ich doch gar nicht
Dann überleg dir was du willst. Für allgemeines sinnfreies gelabere über
goto und blöken stehe ich nicht zur Verfügung.
Cyblord -. schrieb:> Du kannst auch in C direkt zu jeder Adresse springen. Nimmt man z.B. für> Sprünge in den Bootloader.
Mit welchem Komando denn? Ein Funktionspointer speichert doch die
Rücksprungadresse im Stack. Kommt also nicht in Frage,wenn man das RET
des Bootloaders nutzen will. Also Goto. Aber das kann keine Adressen.
Oder eine Art "ASM jump" ? Weiß gerade nicht genau, was du meinst ...
Cyblord -. schrieb:> Dann überleg dir was du willst. Für allgemeines sinnfreies gelabere über> goto und blöken stehe ich nicht zur Verfügung.
Ich auch nicht. Aber google nach Goto, und man weiß, was einem blüht.
Das will ich vermeiden.
Was ich will, habe ich geschrieben.
Jörg W. schrieb:> Mir ist aber in knapp 30 Jahren C-Praxis noch nichts untergekommen, wo> ich sowas als vorteilhaft erachtet hätte. ;-)
Danke. Ich habe noch keine 30 Jahren C, aber bei mir wird das goto kein
Standard werden. Hätte ja schon mal irgendwann ein Fall auftreten
müssen, ist aber nicht.
Gewisse Dinge mögen selten sein. Aber es gibt Fälle, wo "seltsame
Methoden" eine gute Lösung sind.
Jörg W. schrieb:
...
Ja, ist genau das, was ich gesucht habe :-)
Über Labeladresse + Labelvariable findet sich bei Google fast nichts.
Labeladressen lassen sich mit && auslesen, in einem void * ptr;
speichern und mit goto * ptr; aufrufen. Nur wer es mal braucht.
Als Sinn fällt mir ein Prozess-Dispatcher ein. Vielleicht werde ich die
Modul-Sourcen i.d. ISR, die aktuell noch sequentiell ablaufen, via
Jumptable in Prozesse aufteilen. Mal sehen.
Danke jedenfalls.
Frotho schrieb:> Als Sinn fällt mir ein Prozess-Dispatcher ein.
Sowas sollte man aber in der Tat auch mit Funktionszeigern machen
können, und die sind halt C-Standard.
Frotho schrieb:> Cyblord -. schrieb:>>> Du kannst auch in C direkt zu jeder Adresse springen. Nimmt man z.B. für>> Sprünge in den Bootloader.>> Mit welchem Komando denn? Ein Funktionspointer speichert doch die> Rücksprungadresse im Stack.
Na und? Man springt halt nie zurück. Ist beim Bootloader meistens egal.
Jörg W. schrieb:> Frotho schrieb:>> Als Sinn fällt mir ein Prozess-Dispatcher ein.>> Sowas sollte man aber in der Tat auch mit Funktionszeigern machen> können, und die sind halt C-Standard.
Ja natürlich kann man das. Es ist aber ein Unterschied, ob ich die eine
Funkion (ISR) in 9 Funktionen auslagere, mitsamt dem Overhead
Parameterübergabe & Co, oder ob die Bearbeitung in der Kapsel bleibt.
Vielleicht ist das auch Geschmacksache. Ich versuche, die Anzahl
Funktionen niedrig zu halten. Liegt vlt. auch daran, dass ich mich ewig
quäle mit der Namensgebung. Egal warum, ein "jump[index]" ziehe ich bei
zeitkritischen Routinen dem "normalen" Aufruf über Funktionszeigerarray
vor. Wir o.g., gibts auch durch Paramter und Results Overhead, was i.d.
ISr nicht sein muss, finde ich jedenfalls.
Frotho schrieb:> Ja natürlich kann man das. Es ist aber ein Unterschied, ob ich die eine> Funkion (ISR) in 9 Funktionen auslagere, mitsamt dem Overhead> Parameterübergabe & Co, oder ob die Bearbeitung in der Kapsel bleibt.
Du solltest dich von Vorstellungen lösen, die offensichtlich von
Maschinen mit akutem Registermangel wie einem alten x86 herrühren. Auf
vernünftigen Maschinen kostet eine Parameterübergabe in eine Funktion
rein gar nichts, da sie in Registern abgehandelt wird. Ob überhaupt
Stack dafür benötigt wird, ist auch bei einer Funktion nicht völlig
klar. Wichtig ist es in C, den Scope der Funktionen klein zu halten
(static), damit der Compiler weiß, dass sie wirklich nur an dieser
Stelle gebraucht werden. U. U. kann er dann auch alles inline erweitern
und die Funktionsaufrufe komplett eliminieren.
Jörg W. schrieb:> Du solltest dich von Vorstellungen lösen, die offensichtlich von> Maschinen mit akutem Registermangel wie einem alten x86 herrühren. Auf> vernünftigen Maschinen kostet eine Parameterübergabe in eine Funktion> rein gar nichts, da sie in Registern abgehandelt wird. Ob überhaupt> Stack dafür benötigt wird, ist auch bei einer Funktion nicht völlig> klar
Beim TE mangelt es offensichtlich nicht an Speicher sondern an
kognitiven Möglichkeiten Programme sinnvoll zu strukurieren.
Ich kenne ja die Diskussion mit OOP-Gegnern.
Aber jemanden der sogar strukurierte Programmierung mittels Funktionen
ablehnt, ist mir schon lange nicht mehr untergekommen.
Jörg W. schrieb:> Du solltest dich von Vorstellungen lösen
Ja kann sein. Ich habe mal Interpreter geschrieben und davor TSRs. x86
stimmt genau, sogar noch 286 + 386, einen Z80 Interpreter als Vorbild.
Die Z80 Sourcen habe ich noch im Kopf. Das absolute Paradies, aber eben
Overhead. Bei C kenne ich die interen Strukturen nicht. Ich vermute aber
mal, dass im Code von "Funktionen" nicht mehr viel zu sehen ist.
Frotho schrieb:> Jörg W. schrieb:>> Du solltest dich von Vorstellungen lösen> Ich vermute aber> mal, dass im Code von "Funktionen" nicht mehr viel zu sehen ist.
Wie mans nimmt, eine Funktion fängt normal mit einem label an und endet
mit einem ret. So versteckt ist das nun nicht. Wenn man nicht gerade
extreme Optimierung macht.
Das hängt auch weniger von C ab, als vielmehr von der Zielarchitektur.
Nur, welche Relevanz hat die ASM Repräsentation für diese Diskussion
überhaupt? Es geht um die Lesbarkeit des C Quellcodes.
Cyblord -. schrieb:> Frotho schrieb:>> Jörg W. schrieb:>>> Du solltest dich von Vorstellungen lösen>>> Ich vermute aber>> mal, dass im Code von "Funktionen" nicht mehr viel zu sehen ist.>> Wie mans nimmt, eine Funktion fängt normal mit einem label an und endet> mit einem ret. So versteckt ist das nun nicht. Wenn man nicht gerade> extreme Optimierung macht.
Wobei Funktions-Inlining für mich jetzt keine extreme Optimierung ist,
aber da kann man sicher drüber diskutieren... (solange der Scope, die
Sichtbarkeit der Funktion nicht ausreichend beschränkt ist, wird sie
natürlich trotzdem angelegt, aber ggf. nie angesprungen)
> Nur, welche Relevanz hat die ASM Repräsentation für diese Diskussion> überhaupt? Es geht um die Lesbarkeit des C Quellcodes.
Da sprach jemand von Overhead durch Funktionsaufrufe, den man in der
ASM-Repräsentation vermutlich am Besten sehen kann.
MfG, Arno
Frotho schrieb:> Kann man die Adresse von Sprungmarken auslesen, um sie in einer> Sprungtabelle zu speichern? Und natürlich wird das passende Gegenstück> benötigt, ein indirekter Jump-Befehl, der eine Adresse in einer> Sprungtabelle ansteuern kann (Goto will ich das nicht nennen, ich> fürchte Schläge ;-) )
Das geht sogar zur Laufzeit: setjmp/longjump
Cyblord -. schrieb:> Nur, welche Relevanz hat die ASM Repräsentation für diese Diskussion> überhaupt? Es geht um die Lesbarkeit des C Quellcodes.
Primär Labelvariable + Sprungtabelle. Die Lesbarbeit ist ein Motiv.
Arno schrieb:> Overhead durch Funktionsaufrufe, den man in der> ASM-Repräsentation vermutlich am Besten sehen kann.
Wie gemeint?
Das bringt doch nichts. Mach dich mal schlau über die moderne
x64 Architektur.
Geschwindigkeit holst du da nur raus, wenn du komplett auf
Sprünge verzichtest, bzw. die Branch Prediction für dich arbeiten
lässt.
Dazu gibt es etwa bedingte Befehleserweiterungen.
Für fühlbaren Geschwindigkeitsgewinn musst du die SIMD (AVX512 etc.)
Erweiterungen verwenden, da wird dann dein lahmer Rechner plötzlich
zum Numbercruncher...
Das hängt aber inzwischen alles vom genauen Prozessormodell ab.
Die x64 Architektur erkennt automatisch Befehlsabhängigkeiten,
und führt mehrere Befehle im Hintergrund parallel aus...
Daneben wird Register-Renaming gemacht, da intern viel mehr Register
vorhanden sind.
Wenn du dich da nicht mal ansatzweise eingelesen hast, hast du
keine Change echte Performance zu erzielen.
Ein guter Link dazu: https://www.agner.org/optimize/
Du brauchst dir nur mal memcpy() Routinen anzuschauen.
Die bessren Routinen (Intel Performance Library) sind so schnell,
wie es der 1st Level Cache zulässt!
Da ist eine einfache Zuweisung in einer for() schleife lahm
dagegen...
Der Assembler Code ist übrigens sehr gut lesbar, wenn du da
noch nicht reingeschaut hast, weisst du noch gar nicht, von was du
überhaupt redest...
Es ist wirklich verlorene Zeit, über solche Microoptimierungen
nachzudenken!
Udo K. schrieb:> Das bringt doch nichts. Mach dich mal schlau über die moderne> x64 Architektur.
ähm..habe unter Mikrocontroller geschrieben
> Es ist wirklich verlorene Zeit, über solche Microoptimierungen> nachzudenken!
Ich habe den Timer (testweise) im Grenzbereich laufen. Da ist nichts
"verlorene Zeit"
Ist schon ein interessantes Thema.
Ich habe mal, leider erfolglos, versucht auf einem Bluepill Board in die
oberen 64kB Funktionen und Zeichensätze für ein ST7735 Display unter zu
bringen.
In den unteren 64kB einen Bootloader und die Anwendung.
Beide sollten die Grafik Funktionen nutzen ohne diese im oberen Bereich
zu verändern.
Bin dann leider nicht weiter gekommen und habe aufgegeben.
Hat das schon einmal jemand geschafft, so das man nur eine Header Datei
einbinden muss und der Compiler sich nicht beschwert und auch nicht
versucht die Funktionen selbst zu bauen?
Frotho schrieb:> Arno schrieb:>> Overhead durch Funktionsaufrufe, den man in der>> ASM-Repräsentation vermutlich am Besten sehen kann.>> Wie gemeint?
Du warst derjenige, der Overhead ins Spiel brachte :) Woher weißt du,
dass ein wie auch immer erstellter Sprung oder ein goto weniger Overhead
hat als ein (*function)()? Dazu wirst du doch sicherlich den vom
Compiler generierten ASM-Code ansehen, oder nicht?
MfG, Arno
Frotho schrieb:> Kann man die Adresse von Sprungmarken auslesen, um sie in einer> Sprungtabelle zu speichern?
Nicht wirklich. Wozu auch? C "Sprungmarken" kann man mit C Sprachmitteln
direkt anspringen. Wenn man eine Funktion z.B. als solche Marke ansieht,
dann kann man durch den Aufruf der Funktion dahin "springen".
Dito Labels für goto oder die case: Marken in einem switch() Statement.
> Und natürlich wird das passende Gegenstück> benötigt, ein indirekter Jump-Befehl, der eine Adresse in einer> Sprungtabelle ansteuern kann
Unter dem vollständigen Verlust von Portabilität kann man einen
geeigneten Datentyp (int oder void*) natürlich in einen Funktionszeiger
casten und dann dahin springen. So macht man das bspw. im schon
genannten Fall des Sprungs in den Bootloader.
> Das ist ja nur theoretisch, eine Art "on <Ausdruck> goto <Sprungmarke>".
Dafür gibt es ja das switch() Statement in C.
Frotho schrieb:> Wer immer nur mit der Herde blökt "goto ist pfui", wird auch immer nur> in seinem (Denk)Gatter bleiben.
Manche Gedanken setzen sich aber auch einfach deswegen als richtig
durch, weil sie eben richtig sind.
> Ein sinnvoller Einsatz> von Goto (außer in absoluten Ausnahmefällen wie bei Fehlern) fällt mir> gerade auch nicht ein (nicht mal in BASIC). Pfui ist es deswegen noch> lange nicht. Gosub habe ich z.B. gerne verwendet.
GOSUB ist ein Funktionsaufruf. Den hast du in C natürlich immer noch.
Nur halt bequemer, mit Namen. Zeilennummern hat man in BASIC nur
deswegen verwendet, weil diese (frühen) BASIC Dialekte noch keine
benannten Funktionen hatten.
> Für Routinen, die an mehreren> Stellen innerhalb einer Funktion dasselbe tun, war Gosub ideal
Häh? Natürlich kannst du auch in C ein und dieselbe Funktion mehrfach
innerhalb einer weiteren Funktion aufrufen.
Was du wahrscheinlich meinst, ist daß du so eine Funktion nicht nur als
Ganzes aufrufen kannst, sondern einen Funktionsaufruf mitten in eine
Funktion hinein. Oder eine andere "Optimierung" die ich hin und wieder
geshen habe: wenn die letzte Operation innerhalb einer Funktion der
Aufrunf einer anderen Funktion ist, dann wird die nicht per CALL/GOSUB
aufgerufen, sondern per JMP/GOTO. Das RET/RETURN am Ende dieser Funktion
beendet dann die erste Funktion gleich mit.
Man spart damit den Stackzugriff für die Returnadresse. Aber das sind
Mätzchen. Der Optimierungseffekt ist jenseits von "Hallo Welt!"
Programmen nicht nachweisbar.
Aber wenn dich C zu sehr von deinen heißgeliebten Assemblertricks
fernhält, dann bleib halt bei Assembler. Kannst dich ja mit dem c-hater
zusammentun.
Arno schrieb:> Woher weißt du,> dass ein wie auch immer erstellter Sprung oder ein goto weniger Overhead> hat als ein (*function)()?
Weil ein Jump nur ein load Programmcounter ist. Weniger (und schneller)
geht gar nicht :)
Funktionsparameter sind in C by value. Wenn 5 Werte übergeben werden,
muss folglich 5x kopiert werden. Wie kann das schneller als ein Jump
sein? Selbst mit & vor dem Parameter wird Code generiert. Nehme ich
jedenfalls mal an.
> Dazu wirst du doch sicherlich den vom> Compiler generierten ASM-Code ansehen, oder nicht?
Ja, das werde ich demnächst garantiert tun.
pegel schrieb:> Ist schon ein interessantes Thema.> Ich habe mal, leider erfolglos, versucht auf einem Bluepill Board in die> oberen 64kB Funktionen und Zeichensätze für ein ST7735 Display unter zu> bringen.
Sowas ähnliches. Es war noch unter DOS. Ich habe mal den zweiten
Zeichensatz der Grafikkarte aktiviert, mit Grafikzeichen geladen und
daraus unter DOS eine Art "aufsetzbares Windows" (mit Fenstern und allem
pipapo) gebaut. Die Grafik wurde mit den Zeichen 0..31 gesteuert, von
CLS bis locate Cursor war alles dabei. Einen Cursor gab es auch, und
Mausbedienung. Ging sogar mit Programmen, die keine Maus hatten, z.B.
alte COBOL-Programme. Es mussten nur die entsprechenden Steuerzeichen
"gedruckt" werden, um die Schnittstelle zum "Windows" zu bedienen.
Rückmeldung kam über ReadKey, auch die Cursorposition. Mein "Windows"
war blitzschnell, und winzig klein, nur ein paar kb. Ja die guten alten
Zeiten. Heute haben wir sie wieder. Das wissen wir aber erst morgen ;)
Axel S. schrieb:>> Ein sinnvoller Einsatz>> von Goto (außer in absoluten Ausnahmefällen wie bei Fehlern) fällt mir>> gerade auch nicht ein (nicht mal in BASIC). Pfui ist es deswegen noch>> lange nicht. Gosub habe ich z.B. gerne verwendet.>> GOSUB ist ein Funktionsaufruf. Den hast du in C natürlich immer noch.
Nein ist es eben nicht. Ich will die Funktion nicht verlassen, weil ich
dann auch den (lokalen) Datenkontext verlasse. Wenn man das noch nie
gebraucht hat, sieht man natürlich keinen Sinn darin. Ist ja auch nicht
weiter schlimm.
> Häh? Natürlich kannst du auch in C ein und dieselbe Funktion mehrfach> innerhalb einer weiteren Funktion aufrufen.
Und wie soll das gehen, wenn ich innerhalb der Funktion z.B. eine
Berechnungsroutine aufrufen will. Die muss doch angesprungen werden, und
danach muss zum Caler zurückgesprungen werden. also genau das, was GOSUB
macht. Oder wo stehe ich jetzt am Schlauch, wie soll das denn in C
gehen?
> Was du wahrscheinlich meinst, ist daß du so eine Funktion nicht nur als> Ganzes aufrufen kannst, sondern einen Funktionsaufruf mitten in eine> Funktion hinein.
Nein. Das habe ich noch nie gebraucht. Ich habe mich vielleicht
undeutlich ausgedrückt. Muster hätte ich in VBA, wenn ich suchen soll
sage es.
> Aber wenn dich C zu sehr von deinen heißgeliebten Assemblertricks> fernhält, dann bleib halt bei Assembler. Kannst dich ja mit dem c-hater> zusammentun.
Quatsch. C gefällt mir immer besser. Nicht so gut wie Assembler, aber
ich habe mich an die d@@fen geschw. Klammern fast gewöhnt :)
Frotho schrieb:> Funktionsparameter sind in C by value. Wenn 5 Werte übergeben werden,> muss folglich 5x kopiert werden. Wie kann das schneller als ein Jump> sein? Selbst mit & vor dem Parameter wird Code generiert. Nehme ich> jedenfalls mal an.
Funktionsparameter lösen sich (zumindest unter selben Bedingungen wie
bei einem goto) meist in nichts auf, wenn man Inlining zuläßt oder gar
erzwingt.
Dann wird da nix kopiert.
Frotho schrieb:> Funktionsparameter sind in C by value. Wenn 5 Werte übergeben werden,> muss folglich 5x kopiert werden.
Dein Weltbild ist außerordentlich simpel. Die Realität mag vor 30 Jahren
so gewesen sein, seither hat sich im Compilerbau einiges getan.
Wenn du Assembler programmieren willst, dann tu's. Wenn du in einer
höheren Sprache programmieren willst, hat das nur Sinn, wenn du deren
Abstraktions- und Strukturierungsmöglichkeiten auch benutzt.
Ja, ich weiß, "Real Programmers can write FORTRAN in any language."
Frotho schrieb:> Arno schrieb:>> Woher weißt du,>> dass ein wie auch immer erstellter Sprung oder ein goto weniger Overhead>> hat als ein (*function)()?>> Weil ein Jump nur ein load Programmcounter ist. Weniger (und schneller)> geht gar nicht :)
Dafür hast du am Ende den Speicheroverhead, um wieder irgendwo definiert
herauszukommen. Und schneller geht sehr wohl: Das Stichwort Inlining
wurde ja schon genannt.
> Funktionsparameter sind in C by value. Wenn 5 Werte übergeben werden,> muss folglich 5x kopiert werden.
Nein, muss es nicht. Das Programm muss sich so verhalten, als wäre
kopiert worden - aber wenn das egal ist (z.B. weil der Parameter nicht
verändert wird) dann muss der Compiler auch keinen Code für das Kopieren
generieren, und wird das wahrscheinlich in den meisten Fällen auch nicht
tun.
>> Dazu wirst du doch sicherlich den vom>> Compiler generierten ASM-Code ansehen, oder nicht?>> Ja, das werde ich demnächst garantiert tun.
Ich rate sehr dazu, das zu tun, bevor dir manche Annahmen wie
Gewissheiten vorkommen. Es gibt verdammt gute Compilerbauer :)
MfG, Arno
Arno schrieb:> Ich rate sehr dazu, das zu tun, bevor dir manche Annahmen wie> Gewissheiten vorkommen. Es gibt verdammt gute Compilerbauer :)
Vielleicht ist mein Weltbild wirklich beschädigt. Mag daran liegen, dass
ich schon zu viele Programme von innen gesehen habe. M$ DOS Kernel war
z.B. die ärmste Traurigkeit, die ich je gesehen habe. Die INTs haben
sogar den Stack neu "initialisiert", bei jedem Aufruf!! Da habe ich
halt gelernt, selbst zu optimieren. Wenn das heute besser ist, würde ich
mich wirklich freuen. Gibt es (deutsche) Literatur, WIE ein Compiler
sich verhält?
Danke allerseits.
Frotho schrieb:> Gibt es (deutsche) Literatur, WIE ein Compiler sich verhält?
Was sollte sowas bringen, wer sollte Zeit haben, das zu schreiben?
Es ist allemal sinnvoll, sich den vom Compiler generierten Code
anzusehen. Ansonsten steigt man dort nur ein, wenn man wirklich am
Compiler mit werkeln möchte, und dann ist Englisch sowieso gesetzt.
Frotho schrieb:> Axel S. schrieb:>>> Ein sinnvoller Einsatz>>> von Goto (außer in absoluten Ausnahmefällen wie bei Fehlern) fällt mir>>> gerade auch nicht ein (nicht mal in BASIC). Pfui ist es deswegen noch>>> lange nicht. Gosub habe ich z.B. gerne verwendet.>>>> GOSUB ist ein Funktionsaufruf. Den hast du in C natürlich immer noch.>> Nein ist es eben nicht.
Albern.
Das GOSUB von BASIC (das meintest du ja wohl) ist sehr wohl ein
Funktionsaufruf. Bzw. das BASIC-Äquivalent dessen, was in C ein
Funktionsaufruf ist. Damals nannte man das UNTERPROGRAMM. Bzw. englisch
SUBROUTINE, daher auch GOSUB für GOto SUBroutine.
> Ich will die Funktion nicht verlassen, weil ich> dann auch den (lokalen) Datenkontext verlasse.
Genauso albern. BASIC hat keine lokalen Kontexte. Da sind alle Variablen
global. Du kannst in C natürlich genauso programmieren, wenn du willst.
Alle anderen haben schon erkannt, daß das eine schlechte Idee<tm> ist.
Aber irgendwer muß ja der letzte sein.
>> Häh? Natürlich kannst du auch in C ein und dieselbe Funktion mehrfach>> innerhalb einer weiteren Funktion aufrufen.>> Und wie soll das gehen, wenn ich innerhalb der Funktion z.B. eine> Berechnungsroutine aufrufen will. Die muss doch angesprungen werden, und> danach muss zum Caler zurückgesprungen werden. also genau das, was GOSUB> macht. Oder wo stehe ich jetzt am Schlauch, wie soll das denn in C> gehen?
Hast du noch nie ein C-Programm geschrieben, wo du eine Funktion
aufrufst?
> Ich habe mich vielleicht undeutlich ausgedrückt.
<Loriot> ACH! </Loriot>
Frotho schrieb:> Gosub habe ich z.B. gerne verwendet.
Gosub hatte man früher in Basic verwendet, da es Konstrukte wie
Funktionen und Prozeduren noch nicht gab. Endlosschleifen mit
Abbruchbedingung konnte man nur mit goto schreiben. Jeder
Assemblerprogrammierer verwendet nichts anderes.
Frotho schrieb:> Und wie soll das gehen, wenn ich innerhalb der Funktion z.B. eine> Berechnungsroutine aufrufen will. Die muss doch angesprungen werden, und> danach muss zum Caler zurückgesprungen werden. also genau das, was GOSUB> macht. Oder wo stehe ich jetzt am Schlauch, wie soll das denn in C> gehen?
Ein Funktionsaufruf vielleicht? Dann springt es dort hin und kehrt am
Schluß wieder zum Aufrufer zurück. Kannst du beliebig schachteln.
Wenn Du noch irgendeinen Kontext mit Daten mitgeben willst übergibst Du
halt noch einen Zeiger auf die Daten.
Gcc kann (nicht-standard!) auch lokale Funktionen (Funktionen innerhalb
von Funktionen), die sind wie lokale Variablen auch nur lokal sichtbar
und haben Zugriff auf alle lokalen Variablem der äußeren Funktion. Die
kann man auch beliebig schachteln. Pascal-Programmierer werden das zu
schätzen wissen, es kann manchmal ganz nützlich sein. Aber Achtung: Das
sind keine Closures, nicht daß jemand auf komische Ideen kommt, das ist
alles weiterhin rein Stackbasiert und die kann man nicht nach außen
weiterreichen!
Funktionen sind kein Äquivalent zu gosub, weil Funktionen nur einen
Einsprung haben. Mit gosub beliebig viele, wenn man will.
Aber es gäbe für alles eine Lösung...
A. S. schrieb:> Funktionen sind kein Äquivalent zu gosub, weil Funktionen nur einen> Einsprung haben.
Selbst dafür hat GCC noch eine Extension, soweit ich mich erinnere –
aber auch die gehört zu den Dingen "mal gehört, nie gebraucht".
Frotho schrieb:> M$ DOS Kernel war z.B. die ärmste Traurigkeit, die ich je gesehen habe.
Und, was vermutest Du, in welcher Programmiersprache das geschrieben
wurde?
In C jedenfalls nicht; zu den Zeiten gab es noch gar keine vernünftigen
C-Compiler.
Rufus Τ. F. schrieb:> zu den Zeiten gab es noch gar keine vernünftigen C-Compiler.
MS-DOS ist 10 Jahre jünger als UNIX (sieht man schon an der "Epoche":
UNIX zählt ab 1.1.1970, MS-DOS/FAT ab 1.1.1980), und C ist geschrieben
worden, damit man UNIX nicht mehr (nur) in Assembler schreiben musste …
Jörg W. schrieb:> Rufus Τ. F. schrieb:>> zu den Zeiten gab es noch gar keine vernünftigen C-Compiler.>> MS-DOS ist 10 Jahre jünger als UNIX (sieht man schon an der "Epoche":> UNIX zählt ab 1.1.1970, MS-DOS/FAT ab 1.1.1980), und C ist geschrieben> worden, damit man UNIX nicht mehr (nur) in Assembler schreiben musste …
Zu den Zeiten gab es noch gar keine vernünftig optimierenden
C-Compiler.
Die Sprache war noch nicht mal so weit, als daß das überhaupt -
zumindest in dem Maß, wie das heute möglich ist - gegangen wäre.
Markus F. schrieb:> Zu den Zeiten gab es noch gar keine vernünftig optimierenden C-Compiler.
Trotzdem wurde UNIX in C geschrieben. ;-)
https://www.quora.com/What-is-UNIX-How-is-it-related-to-C-and-C++
"In 1972 (I think, or ‘73) they wanted to deploy their system on
platforms other than the original PDP-11. They wanted to rewrite the
kernel in a high level language, which was something of a blasphemy at
the time, no one ever heard about an OS kernel that wasn’t in assembly,
nor did they imagine one. The high level languages at the time weren’t
low level enough, so they had to invent a middle level language to suit
their only need: write an (almost) cross-platform OS kernel. And C was
born."
Natürlich ist das auch miteinander verwoben. Operatoren wie ++ und --
sind vermutlich vor allem deshalb erfunden worden, weil eben eine PDP-11
sowas wie post-increment und pre-decrement bei Zeigerzugriffen bereits
in ihrer CPU hatte. Daher findest du in alten C-Quelltexten praktisch
auch nur *p++ und *--p, aber nicht anders herum (*p--, *++p). Auf diese
Weise konnte man trotz noch nicht allzu gut entwickelter Optimierungen
im Compiler trotzdem recht gut auf die CPU abbildbaren Code verfassen.
Optimierung auf Quelltextebene … im Prinzip das, was unser TE macht.
Nur, dass er dafür halt 40 Jahre zu spät dran ist, mittlerweile braucht
man sowas nicht mehr. :)
Rufus Τ. F. schrieb:> Frotho schrieb:>> M$ DOS Kernel war z.B. die ärmste Traurigkeit, die ich je gesehen habe.>> Und, was vermutest Du, in welcher Programmiersprache das geschrieben> wurde?> In C jedenfalls nicht; zu den Zeiten gab es noch gar keine vernünftigen> C-Compiler.
Zumindest nicht in Bill Gates' Garage. Bei den "großen Jungs" bei den
Bell Laboratories durchaus. Billie spielte damals noch mit BASIC.
Ungefähr das Level, auf dem der TE hängen geblieben ist :(
Markus F. schrieb:> Jörg W. schrieb:>>>> MS-DOS ist 10 Jahre jünger als UNIX (sieht man schon an der "Epoche":>> UNIX zählt ab 1.1.1970, MS-DOS/FAT ab 1.1.1980), und C ist geschrieben>> Zu den Zeiten gab es noch gar keine vernünftig optimierenden> C-Compiler.
Für einen Betriebssystem-Kernel hat C damals schon gereicht. Nicht daß
es von Anfang an perfekt gewesen wäre. Aber wenn es gut genug für UNIX
war, wäre es mehr als gut genug für DOS gewesen.
Aber natürlich wissen wir alle, daß DOS als Abklatsch von CP/M gestartet
ist. Und letzteres war in zum größten Teil in Assembler, in Teilen in
PL/M geschrieben.
Axel S. schrieb:> Billie spielte damals noch mit BASIC.
Nun, er schrieb das BASIC. Genauer: hat es zum Standard für alle
Heimcomputer und erste PCs gemacht.
Zudem hat Microsoft DOS nicht entwickelt sondern gekauft.
Axel S. schrieb:> Aber wenn es gut genug für UNIX war, wäre es mehr als gut genug für DOS> gewesen.
Naja, qdos brauchte nicht portabel zu sein.
Ganz in Ruhe lässt mich das Thema mit den Funktionen im oberen 64k
Bereich des Bluepill doch noch nicht.
Nach dieser Methode war es kein Problem, Funktionen und Variablen an die
gewünschte Adresse zu legen:
http://blog.atollic.com/using-gnu-gcc-on-arm-cortex-devices-placing-code-and-data-on-special-memory-addresses-using-the-gnu-ld-linker
Gescheitert bin ich daran, die neue Anwendung dazu zu bewegen die
vorhandenen Funktionen im oberen Bereich zu benutzen.
Wenn ich im linker script den oberen Bereich angebe, versucht der
Compiler dort alles neu zu bauen und da fehlen natürlich die Quellen
dazu.
So ist das auch gedacht.
Könnte man eine Funktionstabelle an den Anfang des oberen Bereiches
legen die Name und Adresse von Funktion und Variable enthält die vom
Compiler wie eine Bibliothek gefunden werden?
Also ohne diese neu zu bauen und einfach durch eine Header Datei
einzubinden?
A. S. schrieb:> Nun, er schrieb das BASIC. Genauer: hat es zum Standard für alle> Heimcomputer und erste PCs gemacht.
Erste PCs: naja, vielleicht. Wenngleich er da schon gegen bswp.
Turbo-Pascal anstinken musste.
Heimcomputer? Nee, da waren andere vor ihm. Sowas wie C64 ist einfach
älter als QuickBasic.
Billy war geschäftstüchtig, aber innovativ war er nie. Man hätte sich
auch für den 8086-PC bereits etwas besseres als einen CP/M-Abklatsch
vorstellen können – siehe Commodore Amiga oder Atari ST.
> Zudem hat Microsoft DOS nicht entwickelt sondern gekauft.
Hat er, aber damals hat er (bzw. Paul Allen) auch tatsächlich noch
selbst Hand angelegt.
Jörg W. schrieb:> Heimcomputer? Nee, da waren andere vor ihm.> Sowas wie C64 ist einfach älter als QuickBasic.
Das Commodore-Basic ist aber auch von Microsoft...
genauso wie das Basic auf dem Atari.
Cyblord -. schrieb:> Schon bisschen peinlich wie man Microsoft und Bill Gates immer künstlich> kleinreden muss.
Wo habe ich ihn „klein geredet“?
Ich habe nur geschrieben, dass er alles andere als innovativ war. Einen
Gegenbeweis hast du nicht, nur Polemik.
Davon abgesehen ging's um Programmiersprachen und insbesondere C. Nicht
gerade eine Domäne von Microsoft – so gut wie alles jenseits von C89
haben sie „verschlafen“ bzw. bewusst nichts mehr in der Richtung
gemacht. Damit dürften sie unter den C-Compilern größerer Hersteller so
ziemlich das unbestrittene Schlusslicht sein.
Außerdem ist es natürlich interessant, dass jeder, der ein paar
Argumente gegen Microsoft vorträgt, sofort ein „Linuxer“ ist. Das
spricht Bände … es geht eben nichts über ein gepflegtes Feindbild. :)
S. R. schrieb:> Jörg W. schrieb:>> Heimcomputer? Nee, da waren andere vor ihm.>> Sowas wie C64 ist einfach älter als QuickBasic.>> Das Commodore-Basic ist aber auch von Microsoft...> genauso wie das Basic auf dem Atari.
Ah OK. War mir so nicht bewusst, gerade mal nachgelesen.
Jörg W. schrieb:> A. S. schrieb:>>> Nun, er schrieb das BASIC. Genauer: hat es zum Standard für alle>> Heimcomputer und erste PCs gemacht.>> Erste PCs: naja, vielleicht. Wenngleich er da schon gegen bswp.> Turbo-Pascal anstinken musste.>> Heimcomputer? Nee, da waren andere vor ihm. Sowas wie C64 ist einfach> älter als QuickBasic.
Vorsicht!
Das Commodore BASIC im C64 ist eine nur geringfügig modifierte Variante
des Microsoft BASIC für 6502 [1]. Und ja, diesen BASIC Interpreter hat
William Henry tatsächlich selber geschrieben. Oder doch zumindest zum
größten Teil. Der Original XT hatte neben dem BIOS auch ein BASIC im
ROM.
[1] https://en.wikipedia.org/wiki/Commodore_BASIC
Jörg W. schrieb:> Billy war geschäftstüchtig, aber innovativ war er nie. Man hätte sich> auch für den 8086-PC bereits etwas besseres als einen CP/M-Abklatsch> vorstellen können – siehe Commodore Amiga oder Atari ST.
Bill Gates ist mit Basic Millionär geworden und hat es in den 70ern zum
Standard gemacht.
IBM kam zu Microsoft, weil es auf praktisch jedem Rechner lief und
bekannt war. Mit Betriebssystemen hatten sie jedoch keine Erfahrung, so
dass sie zeitlich und fachlich sicher nicht in der Lage war, da was
eigenes zu entwickeln.
Ob der Digital-Research-Boss nun Angeln war, als IBM ankloppfte (auf
Gates Empfehlung hin), ist am Ende egal, für Microsoft war es ein
Glücksfall. Aber das schlechte DOS kann man ihm kaum vorwerfen, das war
weder seine Domäne noch sein Anspruch (da kompetent zu sein).
Axel S. schrieb:> Vorsicht!
Yo, hatte ja kurz vor dir schon jemand angemerkt.
Seit ich Turbo-Pascal hatte (schon auf CP/M), brauchte ich aber kein
BASIC mehr. :)
A. S. schrieb:> Aber das schlechte DOS kann man ihm kaum vorwerfen, das war weder seine> Domäne noch sein Anspruch (da kompetent zu sein).
Nö, er hat es halt nur verkauft. Sowas konnte er immer gut. :) Das es
"quick and dirty" hieß, schien ihn aber schon gestört zu haben, es
musste dann noch schnell umbenannt werden …
> Der Original XT hatte neben dem BIOS auch ein BASIC im ROM.
Bis in die 486/Pentium-Zeit gab es dann ja auch die bekannte
Fehlermeldung "no basic ROM found", wenn kein Bootsector gefunden wurde.
Ursprünglich war es halt so, daß ein Computer immer mit
Programmiersprache geliefert wurde. (War auch sinnvoll, weil es für
viele Modelle kaum Software gab.)
IBM hat die Marktchancen der PCs einfach stark unterschätzt, sonst
hätten sie vermutlich ein eigenes OS entwickelt. Später haben sie dann
noch OS/2 nachgeschoben, aber da war es bereits zu spät.
Angeblich sollte der Raspi an diese Tradition anknüpfen und mit einem
Python-Interpreter im ROM ausgestattet werden, daher auch das PI im
Name.
Und BTT: BASIC ohne goto und gosub wäre kaum vorstellbar. ;-))
svensson schrieb:> Ursprünglich war es halt so, daß ein Computer immer mit> Programmiersprache geliefert wurde.
Naja, nicht wirklich: CP/M-Computer (die man sicherlich als eine Art
Vorläufer der PCs ansehen kann, eine andere Linie als all die
Heimcomputer) hatten von Haus aus nichts dabei.
Jörg W. schrieb:> Naja, nicht wirklich: CP/M-Computer (die man sicherlich als eine Art> Vorläufer der PCs ansehen kann, eine andere Linie als all die> Heimcomputer) hatten von Haus aus nichts dabei.
Ich meine, beim Schneider (Amstrad CPC) wäre damals eine Diskette
dabeigelegen. Weiß aber nicht mehr ganz genau.
A. S. schrieb:> IBM kam zu Microsoft, weil es auf praktisch jedem Rechner lief und> bekannt war. Mit Betriebssystemen hatten sie jedoch keine Erfahrung, so> dass sie zeitlich und fachlich sicher nicht in der Lage war, da was> eigenes zu entwickeln.
Dass es allein mit fehlender Erfahrung erklärbar ist, dass man einen
Adressraum oben dich macht, stelle ich in Zweifel. Das darf einem
Schüler passieren, aber keiner Weltfirma. Dieser Schnellschuss hat
jahrelang der Fachwelt extremste Probleme bereitet. Aber da haben sich
IBM, Microsoft und Intel die Hand gegeben: von allem nur das
allerschlechteste.
Ich kam damals aus einer Z80-Architektur (CPC 464,15 bekannte Fehler im
OS) und dachte, mich trifft der Schlag ....
Frotho schrieb:> A. S. schrieb:>> Dass es allein mit fehlender Erfahrung erklärbar ist, dass man einen> Adressraum oben dich macht, stelle ich in Zweifel. Das darf einem> Schüler passieren, aber keiner Weltfirma. Dieser Schnellschuss hat> jahrelang der Fachwelt extremste Probleme bereitet. Aber da haben sich> IBM, Microsoft und Intel die Hand gegeben: von allem nur das> allerschlechteste.
Den auf 640kB limitierenden Graphikspeicher hat der Bill aber nicht
eingelötet. Und er hat der CPU auch keine Adressleitungen abgezwickt.
> Ich kam damals aus einer Z80-Architektur (CPC 464,15 bekannte Fehler im> OS) und dachte, mich trifft der Schlag ....
Vielleicht sollte die 640k-Grenze aber bei den Z80-Usern einen
Wiedererkennungseffekt bewirken ;-)