Hallo liebe Community !
ich habe eine Frage zu Sprüngen von Funktion zu Funktion.
Mein Hauptprogramm zum Einlesen eines Protokolls besteht Großteils aus
Funktionen.
while (1)
{
praemabel();
startbit();
Einlesen1();
Zwischenbit();
Einlesen2();
Wenn eine Funktion durchlaufen wurde, erfolgt der Rücksprung in das
Hauptprogramm und ruft dadurch die Funktion in der nächsten Zeile auf.
Ich möchte die Funktion "Zwischenbit" nun entweder durchlaufen und
dadurch in "Einlesen2" springen, oder es erfolgt ein Sprung innerhalb
der Funktion "Zwischenbit" zurück in "praemabel".
Ich bin nur nicht sicher was passiert, wenn ich aus einer Funktion in
eine andere Funktion Springe.
Muss/Sollte eine Funktion immer "durchlaufen/abgeschlossen" werden ?
Hat er die Ursprungsfunktion "Zwischenbit" noch irgendwo hinterlegt, was
später zu einem ungewollten Rücksprung zu "Zwischenbit" führen kann?
void Zwischenbit(void)
{
while (dcccount == 0)
{
}
if (dccbit == 1)
praemabel(); <- Hier wird ja die Funktion "Zwischenbit" nie beendet ?
}
Ich hoffe, die Frage verständlich formuliert zu haben.
Danke für eure Hilfe !!
Philipp L. schrieb: > praemabel(); <- Hier wird ja die Funktion "Zwischenbit" nie beendet ? Nur, wenn die Funktion praemabel() eine Endlasschleife darstellt, wird sie nicht beendet. Ansonsten führt sie am Ende einen Rücksprung durch und landet in der nächsten Zeile nach ihrem Aufruf. NB: Schreibt man das nicht praeambel()? NB2: Bist du sicher, das du gleich mit einem DCC Dekoder anfangen willst? Mach doch erstmal was einfacheres.
Gast
#5730411
Philipp L. schrieb: > Ich bin nur nicht sicher was passiert, wenn ich aus einer Funktion in > eine andere Funktion Springe. Die Aufrufe werden verschachtelt. Philipp L. schrieb: > Hat er die Ursprungsfunktion "Zwischenbit" noch irgendwo hinterlegt Ja! Auf dem Stack. Gebe Zwischenbit einen Rückgabewert. In der main() prüfst du den und rufst dementsprechend Einlesen2() auf oder springst zurück an den Anfang der Schleife. Es ist zwar theoretisch möglich mit setjmp() oder Inline-Assembler-Tricks direkt in eine andere Funktion zu springen, das bewirkt aber einen unübersichtlichen unsauberen Programmablauf. Besser ist es, Funktionen normal zu durchlaufen und über Rückgabewerte zu signalisieren, was danach passieren soll.
Was ist eine "Praemabel"? Meintest du vielleicht "Praeambel"? Ich würde sowas als Automat mit einer case-Struktur aufbauen, wobei du den case-pointer ja in deinen Unterfunktionen dann beliebig verändern kannst.
> NB2: Bist du sicher, das du gleich mit einem DCC Dekoder anfangen > willst? Mach doch erstmal was einfacheres. Jep, bin sicher :-) Das Einlesen des ersten Bytes und dessen Adressauswertung funktioniert auch schon. Muss jetzt nur noch die nächsten Bytes einlesen. > Gebe Zwischenbit einen Rückgabewert. In der main() prüfst du den und > rufst dementsprechend Einlesen2() Das mit den Rückgabewerten habe ich zwar durchgelesen, aber es funktioniert noch nicht wirklich. Hier mal ein Test mit einem festen Rückgabewert von 5 uint8_t Zwischenbit(void) { while (startcount == 0) { } return 5; } Nach durchlaufen der Funktion müsste doch in "Zwischenbit" der Wert 5 gespeichert sein. Wenn ich dies aber in der Main prüfen möchte, erscheint der Fehler: comparison between pointer and integer. if (Zwischenbit == 5) PORT_B1 = 1; else PORT_B1 = 0; Kann ich also die Funktion Zwischenbit nicht als Wert abfragen? Danke!!
Gast
#5730450
Philipp L. schrieb: > Nach durchlaufen der Funktion müsste doch in "Zwischenbit" der Wert 5 > gespeichert sein. Der wird nicht "in Zwischenbit" gespeichert. Der ist temporär als Wert des Ausdrucks "Zwischenbit()" abgelegt. Philipp L. schrieb: > if (Zwischenbit == 5) Das ist Blödsinn. Du vergleichst die Adresse der Funktion im Speicher mit 5. So geht es:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
Du solltest dringend ein Buch über die absoluten Grundlagen lesen. So klappt das nicht.
Philipp L. schrieb: > Kann ich also die Funktion Zwischenbit nicht als Wert abfragen? Du solltest Dir mal Dein C-Buch zu Gemüte nehmen. Dir fehlen eklatante Grundlagen an sehr elementaren Stellen. Wie wird in C eine Funktion aufgerufen? Wie sieht die Syntax dafür aus? Ich halte es nicht für sinnvoll, Dir hier mit Detailkorrektoren "weiterzuhelfen", denn damit lernst Du die Dir fehlenden Grundlagen nicht, sondern kopierst nur munter weiter irgendwo gefundene Versatzstücke ohne Verständnis zusammen. Das mag jetzt vielleicht unfreundlich und hart klingen, ist aber so.
> Du solltest Dir mal Dein C-Buch zu Gemüte nehmen. Ist ständig neben dem Rechner und hilft mir an vielen Stellen weiter. > if (Zwischenbit() == 5) > Einlesen2(); Danke! Ich konnte auch mit Hilfe des Buches nicht herausfinden, dass ich eine Funktion auch innerhalb der If-Bedingung aufrufen kann. >Dir fehlen eklatante Grundlagen an sehr elementaren Stellen. Das ist korrekt und wird mir auch noch an anderen Stellen begegnen. Dafür fange ich ja mit C erst an. ich lerne aber lieber anhand von konkreten Projekten, innerhalb dessen ich dann verschiedene Themen erlerne. z.B. hat es mich sehr gefreut, dass ich das Protokoll bis zum ersten Byte lesen kann und dies auch wunderbar funktioniert. Natürlich habe ich nebenbei auch kleine Testprogramme, in denen ich bestimmte Grundlagen außerhalb des Hauptprojektes teste und dazu lerne.
Gast
#5730467
Philipp L. schrieb: > Ich konnte auch mit Hilfe des Buches nicht herausfinden, dass ich eine > Funktion auch innerhalb der If-Bedingung aufrufen kann. Dann ist das ein ziemlich schlechtes Buch... Das Problem an C und C++ ist dass es sehr viele Fallen gibt. Man kann alle möglichen Dinge hinschreiben die den Anschein haben zu funktionieren, aber trotzdem falsch sind und früher oder später dann nicht mehr gehen. Wenn man nur mit Try&Error lernt, lernt man diese Dinge nicht.
> Man kann alle möglichen Dinge > hinschreiben die den Anschein haben zu funktionieren, aber trotzdem > falsch sind und früher oder später dann nicht mehr gehen. Wenn man nur > mit Try&Error lernt, lernt man diese Dinge nicht. Wie kann denn ein Anfänger sonst etwas lernen. Ich teste Befehle anhand von kleinen Testprojekten. Wenn es funktioniert und ich der Meinung bin es verstanden zu haben, dann kommt das nächste Thema dran. Alle bis dahin verstanden Dinge werden verwendet.
Gast
#5730478
Philipp L. schrieb: > Wie kann denn ein Anfänger sonst etwas lernen. Mit einer weniger heimtückischen Sprache anfangen (Ruby, Python, Java) um die Grundlagen der Programmierung zu lernen. Dann ein C-Buch von vorne bis hinten durcharbeiten und die Übungen machen, aber dabei nicht vorgreifen, weil man dadurch ggf. falsche Annahmen über die Ergebnisse eines Experiments macht.
Ich glaube in C würde ich es lassen, erzeugt dort wahrscheinlich mehr Probleme als es an Nutzen bringt. In Assembler kannst Du jede Schweinerei machen, zu der der Controller fähig ist. Also wenn Du dem Controller sagst JMP von einer einer Funktion irgendwo hin, dann macht der das. Ob man es tatsächlich so machen sollte, auch mit Hinblick darauf, daß evtl. Teile des Codes in anderen späteren Projekten wiederverwendet werden könnten, finde ich aber auch fragwürdig. Also wenn keine Notwendigkeit besteht, auf einzig und allein diese Weise die letzten 20 Byte Flash zu bekommen die man noch braucht, dann würde ich es nicht machen.
Gast
#5730503
Dr. Sommer schrieb: > Mit einer weniger heimtückischen Sprache anfangen (Ruby, Python, Java) > um die Grundlagen der Programmierung zu lernen. Dann fehlt einem aber später evtl. die Motivation sich mit solch seltsamen mühsamen Kram wie C zu beschäftigen ;-) Einfach mal machen passt schon. Ist ja offensichtlich Hobby. Und das Verständnis kommt schon nebenbei.
Gast
#5730504
@ Phillip Man kann so lernen, aber es ist äusserst mühsam und erfordert, dass man streng zwischen den ausdrücklichen Aussagen des Buches und seinen eigenen Vermutungen bzw. Schlussfolgerungen unterscheidet. Das ist Dir in dem Fall von >Wenn ich dies aber in der Main prüfen möchte, erscheint der Fehler: > comparison between pointer and integer.
1 | |
2 | |
3 | |
4 | |
> Kann ich also die Funktion Zwischenbit nicht als Wert abfragen?
nicht gelungen.
Es wird nämlich in dem ganzen C-Buch nicht behauptet werden, - wenn es
nicht schlichter Müll ist -, dass der Funktionsname für den Rückgabewert
dieser Funktion steht.
Das ist also nur Deine eigene Vermutung gewesen, der Du Dir entweder
nicht bewusst warst, oder die Du nicht hinterfragt hast, als der
Compiler die Fehlermeldung ausgab.
Die Fehlermeldung sagt implizit aber eindeutig, dass der Funktionsname
einem Zeiger entspricht und nicht, wie von Dir erwartet, einem Integer.
Verstehe mich recht: Ich behaupte nicht, dass Deine Vermutung von vorne
herein unplausibel war. Solche Vermutungen hängen aber stark von den
eigenen Vorerfahrungen ab und können also fallweise völlig daneben
gehen.
Wenn Du also mit Deiner Methode einigermaßen effizient lernen willst,
musst Du konsequent vorgehen. Du musst streng zwischen dem, was in dem
Buch steht und Deinen Vermutungen darüber unterscheiden, was nicht darin
steht oder was Du einfach noch nicht gelesen hast. Und Du musst Deine
Vermutungen hinterfragen, spätestens wenn sie offensichtlich nicht
zutreffen.
Kürzer und noch effizienter ist der Weg, ein Kapitel bzw. ein
Unterkapitel zunächst vollständig zu erfassen und zu verstehen.
Noch besser, der Weg, dann jeweils die Übungsaufgaben zu machen.
Und noch besser, zunächst mal das ganze Buch zu lesen - erst einmal um
einen Überblick zu bekommen und dann noch einmal, um die einzelnen
Punkte nachzuvollziehen.
Wir kommen hier mittels Text nicht weiter. Das ist eine Grundsatzdiskussion, für die du mich kennen müsstest oder wir ein Gespräch führen müssten. Es ist schön, hier immer gute Antworten zu bekommen.
Gast
#5730518
Dr. Sommer schrieb: > Du solltest dringend ein Buch über die absoluten Grundlagen lesen. So > klappt das nicht. In diesem Fall wird es schon helfen, alle Warnungen des Compilers zu aktivieren und dann auch zu beachten.
1 | |
bzw. in der Arduino IDE unter Voreinstellungen/Compiler Warnungen: alle. Es gibt keinen vernünftigen Grund, Compiler-Warnungen zu ignorieren. Deswegen gibt es auch keinen vernünftigen Grund, sie (wie Arduino es vorgibt) nicht zu aktivieren. Jede Warnung kann man mit den Mitteln der Sprache loswerden. Und das sollte man auch tun - auch wenn es Mehrarbeit bedeutet. Das gilt im Übrigen auch für alle anderen Programmiersprachen.
Moin, Theor schrieb: > Wenn Du also mit Deiner Methode einigermaßen effizient lernen willst, Theor schrieb: > Du musst streng zwischen dem, was in dem > Buch steht und Deinen Vermutungen darüber unterscheiden, Theor schrieb: > Kürzer und noch effizienter ist der Weg, ein Kapitel bzw. ein > Unterkapitel zunächst vollständig zu erfassen und zu verstehen. > Noch besser, der Weg, dann jeweils die Übungsaufgaben zu machen. Und wo bleibt der Spassfaktor dabei? Ich nehm' hier mal stark an, dass es sich um hobbymaessiges programmierenlernen handelt und nicht darum, als Absolvent eines Informatikstudienganges mit Schwerpunkt Theaterwissenschaften/Politologie jetzt moeglichst schnell und effektiv Sicherheitssysteme fuer Atomraketenzuendsysteme programmieren zu muessen. Ja, mir haben sich auch die Zehennaegel aufgerollt - aber hey - es ist noch kein Meister vom Himmel gefallen; natuerlich programmiert man ordentlichen Stuss am Anfang, und wenn man viel Glueck hat, wird der Stussanteil spaeter kleiner. Philipp L. schrieb: > Wie kann denn ein Anfänger sonst etwas lernen. > Ich teste Befehle anhand von kleinen Testprojekten. > > Wenn es funktioniert und ich der Meinung bin es verstanden zu haben, > dann kommt das nächste Thema dran. > Alle bis dahin verstanden Dinge werden verwendet. Passt. Weiter so! Gruss WK
Zum Ablauf des Programms - das hat nichts mit C zu tun - beschäftige dich mal mit Statemachines (zu Deutsch Zustandsautomaten). Damit regelt man das Lesen und Schreiben komplizierterer Protokolle. Zu deiner Lern"methode": Versuch und Irrtum bringt nur sehr begrenzt etwas. Besonders, wenn du dir darauf aufbauend deine Privat-Philosophie zu einer Programmiersprache zusammenreimst. Die Grundkonzepte lernen, die Details intensiv studieren funktioniert besser, als sich etwas zusammenzuträumen. Das hat nichts mit C als Sprache zu tun. C ist auch nicht heimtückisch. C ist ziemlich simpel. Das als heimtückisch zu bezeichnen zeugt von einer gewissen Boshaftigkeit. >> (Ruby, Ruby (eine Hipster-Programmiersprache die sich auf dem absteigenden Ast befindet) unterstützt mehrere Programmierparadigmen. Viel Spaß die als Anfänger zu lernen und auszusortieren was man braucht. >> Python Eine der Hipster-Programmiersprachen schlechthin. Viel Spaß beim Abzählen von Whitespaces. Dazu eine chaotische Anzahl von Bibliotheken die zu 9o% sowieso nur schlecht dokumentierte Wrapper sind. >> Java) Verwendet im Kern immer noch eine C-Syntax. Kommt schon in der Standard-Edition mit einem API von über 4000 Klassen. Davon sollte man schon ein paar hundert kennen wenn man als Java-Programmierer durchgehen möchte.
Gast
#5730572
Hannes J. schrieb: > Das hat nichts mit C als Sprache zu tun. C ist auch nicht heimtückisch. Dann erkläre doch mal kurz und verständlich, was die drei Bedeutungen des "*" sind :-) Oder was "void (*fptr) (const volatile short*, void (*) (void), void*, int[]) bedeutet. Oder was an if(a << 15) falsch ist. Oder wie man Fehlerbehandlung ohne Speicherlecks hinbekommt. Oder wie man Strings ohne Sicherheitslücken verarbeitet. ... Hannes J. schrieb: > unterstützt mehrere Programmierparadigma Das ist sowieso sehr sinnvoll. Man sollte mehrere verbreitete Paradigmen kennenlernen damit man fürs konkrete Projekt die geeigneten aussuchen kann. Die meisten Sprachen unterstützen mehrere Paradigmen. Hannes J. schrieb: > Viel Spaß beim > Abzählen von Whitespaces. Das erzwungene korrekte Einrücken ist sehr sinnvoll für Anfänger - so muss man es direkt richtig machen. Hannes J. schrieb: > Verwendet im Kern immer noch eine C-Syntax. Die Syntax ist unwichtig. Die Sematik ist komplett anders. Hannes J. schrieb: > Davon sollte man > schon ein paar hundert kennen wenn man als Java-Programmierer durchgehen > möchte. Und das ist schlimmer als die Hundert C-Funktionen die man als C-Programmierer können muss?
Gast
#5730605
Hannes J. schrieb: >>> Python > > Eine der Hipster-Programmiersprachen schlechthin. Viel Spaß beim > Abzählen von Whitespaces. Ist von Vorteil einen guten Texteditor zu nutzen. Dann kann man mühelos gut formatierte Listings tippen. Und das Ergebnis ist dann lesbarer als bei den C Freaks die das halbe Programm in eine Zeile quetschen. Und ab Ende stürzt der Kram ständig ab weil sie bei ihrer ganzen Pointerhampelei den Überblick in ihrem Chaos verloren haben ;-) PS: Ja, auch in C kann man richtig, das ist mir klar. Mir ist auch klar dasan in C++ einfache Stringverarbeitung machen kann ohne in 40 Zeilen Quellcode mit Pointern rumzuspielen. Das ging hier eindeutig gegen Programmierer die der Meinung sind übersichtlicher Quellcode ist für Hipster. Deren C Quellcode kann halt keine Sau lesen.
Dr. Sommer schrieb: >> Das hat nichts mit C als Sprache zu tun. C ist auch nicht heimtückisch. > > Dann erkläre doch mal kurz und verständlich, was die drei Bedeutungen > des "*" sind :-) Multiplikationsoperator:
1 | |
Vier mal fünf. Pointerdefinition/Deklaration:
1 | |
p ist ein Pointer auf int, also eine Variable, die auf eine andere Variable vom Typ int zeigt. Hier ist p nicht initialisiert, d.h. p zeigt irgendwohin.
1 | |
2 | |
In diesem Beispiel wird p so initialisiert, daß es auf die Variable a zeigt. Dereferenzierungsoperator:
1 | |
2 | |
3 | |
4 | |
5 | |
Hier wird der Pointer dereferenziert, d.h. der Wert bestimmt, auf den
der Pointer zeigt.
Welcher Wert landet jetzt in b?
> Oder was "void (*fptr) (const volatile short*, void (*) (void), void*, int[])
bedeutet.
Das ist ein Funktionspointer, der auf eine Funktion mit der Signatur
1 | |
verweist. Der zweite Parameter der Funktion ist wiederum ein Funktionspointer auf eine Funktion mit der Signatur
1 | |
Alle anderen Parameter der Funktion sind Pointer auf verschiedene Datentypen. Die Funktion hat keinen Rückgabewert. Anstelle des letzten Parameters könnte man genausgut int* schreiben, da das in diesem Kontext exakt dasselbe bedeutet. > Oder was an if(a << 15) falsch ist. Falsch ist es nicht, es macht nur selten das, was der Schreiber erwartet und das Verhalten hängt von den Umgebungsbedingungen ab. > Oder wie man Fehlerbehandlung ohne > Speicherlecks hinbekommt. ? > Oder wie man Strings ohne Sicherheitslücken > verarbeitet. ... Indem man die richtigen Funktionen dafür verwendet, bzw. versteht, wo die Probleme liegen.
Beitrag #5730646 wurde von einem Moderator gelöscht.
Gast
#5730647
Na, hoffentlich hat er das jetzt so direkt verstanden...
Gast
#5730653
Naja, in C ist Endrekursion eben kein Bestandteil der
Sprachdefinition.
Aber viele C-Compiler unterstützen Endrekursion. Allerdings ist das Eis
eben recht dünn, auf das man sich begibt, da:
a.) man Funktionen natürlich endrekursiv schreiben muss und
weder eine Warnung noch Fehlermeldung vom Compiler bekommt,
wenn man es (aus Versehen) nicht tut,
b.) man die Tail-Call-Optimierung immer einschalten muss,
c.) bei einem Compiler-Wechsel oder einem Debug-Build
einem alles um die Ohren fliegen kann.
Aber vermutlich wird diese Info vielen Schreiberlingen und Lesern hier
leider nichts nützen.
Schade eigentlich...
Moin, Also bei so vielen Bedenkentraegern wundert's mich nicht, dass wir technologisch den Anschluss verloren haben. Wenn ich C lerne, was kratzen mich denn am Anfang die droelfzehn Bedeutungen des "*"? Was kratzen mich wilde Funktionspointerkonstrukte? Das braucht kein Mensch am Anfang. Wenn ich mir vorstelle, als ich vor ueber einem drittel Jahrhundert am ZX81 fast 24/7 am Werkeln war, da waere einer angekommen, der haette gefragt: "Oh - du programmierst den ja in BASIC - Wieviele Programmierparadigmen unterstuetzt das denn?" Und haette dann die Stirn in Sorgenfalten gelegt, ob meiner sicher unqualifizierten Antwort... Bloss gut, dass es damals noch keine Internetforen gab und meine Eltern eher die Sorge hatten, dass das Kind auch mal 'nen Apfel ist und in der Schlule nicht noch schlechter wird. Gruss WK
Gast
#5730663
Dergute W. schrieb: > Das braucht kein Mensch am Anfang. Die meisten Leute fangen aber nicht nur an. Dergute W. schrieb: > Also bei so vielen Bedenkentraegern wundert's mich nicht, dass wir > technologisch den Anschluss verloren haben. Die Logik verstehe ich nicht. Indem man nur die einfachste Technik verwendet und auf alles komplexere verzichtet behält man den technologischen Anschluss? Die chinesische Technik-Leitkultur benutzt jedenfalls keine ZX81 und auch kein Basic.
Gast
#5730667
Dr. Sommer schrieb: > Oder was an if(a << 15) falsch ist. Oder wie man Fehlerbehandlung ohne > Speicherlecks hinbekommt. Oder wie man Strings ohne Sicherheitslücken > verarbeitet. ... Kommt irgendwann die Auflösung? :-)
Gast
#5730673
zitter_ned_aso schrieb: > Kommt irgendwann die Auflösung? Wenn "a" ein signierter 16bit-Integertyp ist, ist der Shift implementation defined. Die Fehlerbehandlung ist m.E. nicht gut zu lösen. Gängige Ansätze nutzen "goto". In vernünftigen Programmiersprachen gibt's dafür RAII und Exceptions. Das mit den Strings ist komplexer zu erklären, findet man aber bei Google.
Moin, Dr. Sommer schrieb: > Die meisten Leute fangen aber nicht nur an. Da ich hier in diesem Thread schreibe, beziehe ich mich mehr auf den Threaderoeffner als auf "die meisten Leute". Dr. Sommer schrieb: > Die Logik verstehe ich nicht. Indem man nur die einfachste Technik > verwendet und auf alles komplexere verzichtet behält man den > technologischen Anschluss? Ich meine es so, dass man am Anfang durchaus auch mit einfacher Technik und "spielerischem" Ansatz arbeiten sollte, und nicht gleich alles extrem verkopft angehen. Gruss WK
Gast
#5730735
Dr. Sommer schrieb: > Wenn "a" ein signierter 16bit-Integertyp ist, ist der Shift > implementation defined. Nope. Das ist bei *right*-shift so. Hat auch nichts mit 16 Bit zu tun. leo
Gast
#5730745
leo schrieb: > Nope. Das ist bei *right*-shift so. Was ist denn dann 1<<15 auf einer Architektur mit 2er-Komplement, und auf einer mit 1er-Komplement? Beides mal das Gleiche? Die 15 im Beispiel hat was mit der 16 zu tun. Bei 32bit-Integern wäre es dann problematisch bei 31.
Philipp L. schrieb: > Wenn eine Funktion durchlaufen wurde, erfolgt der Rücksprung in das > Hauptprogramm und ruft dadurch die Funktion in der nächsten Zeile auf. Korrekt. Jede Funktion endet hinter ihrem Aufruf. Philipp L. schrieb: > Ich möchte die Funktion "Zwischenbit" nun entweder durchlaufen und > dadurch in "Einlesen2" springen, oder es erfolgt ein Sprung innerhalb > der Funktion "Zwischenbit" zurück in "praemabel". Wo ist das Problem, einfach die Bedingung testen:
1 | |
2 | |
Wird die Bedingung in "Zwischenbit" generiert, kann man sie einfach als Returnwert übergeben:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
Philipp L. schrieb: > praemabel(); <- Hier wird ja die Funktion "Zwischenbit" nie beendet ? Stimmt, es kommt zu einer Rekursion, bis der Stack überläuft.
Gast
#5730786
Dr. Sommer schrieb: >> Nope. Das ist bei *right*-shift so. > > Was ist denn dann 1<<15 auf einer Architektur mit 2er-Komplement, und > auf einer mit 1er-Komplement? Beides mal das Gleiche? Left shift schiebt 0 herein und ist eindeutig. Right shift is meist arithmetisch aber eben nicht immer. leo
Gast
#5730790
leo schrieb: > Left shift schiebt 0 herein und ist eindeutig. Achso, dann hatte ich das falsch in Erinnerung. Wo steht das genau?
Peter D. schrieb: > Philipp L. schrieb: >> praemabel(); <- Hier wird ja die Funktion "Zwischenbit" nie beendet ? > > Stimmt, es kommt zu einer Rekursion, bis der Stack überläuft. Quatsch, sie wird natürlich nach "praemabel" beendet. "praemabel" wird also zweimal ausgeführt.
Gast
#5730796
Also wenn ich folgendes für i386 kompiliere
1 | |
2 | |
3 | |
4 | |
5 | |
kommt -2147483648 heraus. Gilt das auch für Rechner mit 1er-Komplement oder Sign-And-Magnitude?
Nur zur Info, mir ist (und war von Anfang an) bewusst, dass meine Struktur und Ablauf für das Einlesen und die Auswertung des Protokolls bestimmt nicht dem bestmöglichen Code entspricht. Aber darum geht es auch momentan noch nicht. Ich möchte einfach nach und nach meinen Wissensstand erweitern und dies anhand von praktischen Projekten mit Spaß umsetzen. wenn ich mir erst alle Möglichkeiten einer Programmiersprache aneignen soll, bevor ich dies an einem konkreten Projekt umsetze, macht das einfach keinen Spaß. Ich habe einige Punkte auf dem Zettel, welche ich unbedingt noch lernen möchte und die meine Programme besser machen (z.B. Array`s) Aber ich muss erstmal bisher gelerntes anwenden.
Gast
#5730913
Philipp L. schrieb: > Ich bin nur nicht sicher was passiert, wenn ich aus einer Funktion in > eine andere Funktion Springe. Das läßt C so gar nicht zu, wie Du das willst, und das ist auch gut so. Der funktionierende Trick ist, daß Du Deine Funktionen mit Rückgabewerten versiehst und dann abhängig von den Rückgabewerten eine Folgefunktion aufrufst oder auch nicht. Übersichtlich wird es, wenn Du das als endlichen Automaten machst, wie Helmut schon erwähnt hatte, nur daß ich das hier nicht mit Funktionspointern machen würde. Endliche Automaten sind gerade embedded und bei Protokoll-Sachen ein sehr nützliches und verbreitetes Konstrukt. Tante Google bemühen und dann erst mit der C-Umsetzung weitermachen.
> Endliche Automaten sind gerade embedded und bei Protokoll-Sachen ein > sehr nützliches und verbreitetes Konstrukt. Jep, das werde ich machen. Es gibt ganz viele tolle Sachen, welche ich mir auch noch ansehen werde. PS: Mein DCC Programm ist jetzt "fertig". Es liest die Bytes nacheinander in Variablen ein. Das ganze läuft super, wenn auch bestimmt nicht optimal programmiert. Aber ich hatte Spaß und wieder etwas gelernt. ich brauche 510 Bytes für die Protokollauswertung.
Gast
#5731293
Dr. Sommer schrieb: > Also wenn ich folgendes für i386 kompiliere > #include <stdio.h> > > int main () { > printf ("%d\n", (1 << 31)); > } > kommt -2147483648 heraus. Ja, erwartungsgemaess 0x8000. > Gilt das auch für Rechner mit 1er-Komplement > oder Sign-And-Magnitude? Das hat mit dem "Rechner" nichts zu tun und ist was anderes.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
war dein urspruengliches Problem, i.e. der Shift-Rechts von negativen Zahlen.
Philipp L. schrieb: > Ich bin nur nicht sicher was passiert, wenn ich aus einer Funktion in > eine andere Funktion Springe. machbar ist das, aber du musst auch eine Ausstiegsstrategie haben, nicht das du eine Endlosschleife programmierst! Statemachine wurde ja schon genannt! Auch rekursive Aufrufe sind möglich bis der Stack am Ende ist! also immer schön auf Überlauf prüfen.
Gast
#5731316
Joachim B. schrieb: > Philipp L. schrieb: >> Ich bin nur nicht sicher was passiert, wenn ich aus einer Funktion in >> eine andere Funktion Springe. Du springst nicht in eine Funktion (zumindest nicht irgendwo hin), du rufst diese auf - von Anfang an.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
Die Main-Funktion wird halt vom Startup-Code aufgerufen. leo
Gast
#5731320
leo schrieb: >> Was ist denn dann 1<<15 auf einer Architektur mit 2er-Komplement, und >> auf einer mit 1er-Komplement? Beides mal das Gleiche? > > Left shift schiebt 0 herein und ist eindeutig. Das mit den Nullen stimmt, universell eindeutig ist es aber nicht. 1 << 15 ergibt ohne Beschränkung der Bits 32768. Dieser Wert ist in einem 16-Bit Typ nicht mit Vorzeichen darstellbar. Folglich ist diese Operation auf 16-Bit Maschinen undefiniert. Egal ob 2er Komplement, 1er-Komplement oder sonstwie. Hingegen ist x << 15 für vorzeichenloses x stets definiert.
Gast
#5731344
A. K. schrieb: > 1 << 15 ergibt ohne Beschränkung der Bits 32768. Dieser Wert ist in > einem 16-Bit Typ nicht mit Vorzeichen darstellbar Na doch oder? Zahlenbereich bei n-Bits: von -2^(n-1) bis 2^(n-1)-1 Was bei 16 Bits folgenden Zahlenbereich ergibt: -32768 bis 32767
zitter_ned_aso schrieb: > Was bei 16 Bits folgenden Zahlenbereich ergibt: > > -32768 bis 32767 Zeit fürs Bettchen? Seit wann ist 32768 in diesem Bereich enthalten? In der Elektrik gibt es zwar die Regel "Rot ist Blau und Plus ist Minus" aber nicht in C. Ok, besser formuliert: "Dieser Wert ist in einem 16-Bit Typ mit Vorzeichen nicht darstellbar."
Gast
#5731351
positiv? natürlich nicht. aber 1<<15 liefert doch die kleinste 16-Bit Zahl (Zweierkomplement) Warum lässt du das Vorzeichen weg?
zitter_ned_aso schrieb: > aber 1<<15 liefert doch die kleinste 16-Bit Zahl (Zweierkomplement) Mathematisch gesehen kann bei x << y und positivem x nie ein negatives Ergebnis rauskommen. Also erst unbeschränkt rechnen, dann ins Format zu quetschen versuchen. So denkt C. Im Sinn von C wird auch ein ausschliesslich inkrementierter positiver Wert bei vorzeichenbehafteter Rechnung nie negativ. Auf der Maschine vielleicht schon, aber das zählt nicht. Es kann auch eine Exception geben und die Maschine darf dich ohrfeigen. "The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. [...] If E1 has a signed type and nonnegative value, and E1 × 2 E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined."
Gast
#5731365
A. K. schrieb: >> Left shift schiebt 0 herein und ist eindeutig. > > Das mit den Nullen stimmt, universell eindeutig ist es aber nicht. > > 1 << 15 ergibt ohne Beschränkung der Bits 32768. Dieser Wert ist in > einem 16-Bit Typ nicht mit Vorzeichen darstellbar. Du wuerfelst hier {1.2}-Komplement und Left-shift einfach durcheinander. Mit 32bit Integern:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
Was hiesse also nicht darstellbar? Das Left-Shift ist eindeutig logisch. Das wird generiert und ist eindeutig:
1 | |
Die Interpretation des Ergebnisses koennte variieren, wenn man denn glaubt, der Compiler koennte 1-Komplement generieren. leo
Gast
#5731375
A. K. schrieb: > Mathematisch gesehen kann bei x << y und positivem x nie ein negatives > Ergebnis rauskommen. Also erst unbeschränkt rechnen, dann ins Format zu > quetschen versuchen. So denkt C. Wir sprachen hier von C. Die Mathematik kann auch mit Unendlich (und mehr) umgehen. C wurde fuer was anderes erfunden. leo
leo schrieb: > Du wuerfelst hier {1.2}-Komplement und Left-shift einfach durcheinander. > Mit 32bit Integern: 1 << 15 ist auf einer Maschine mit 16-Bit "int" Typ undefiniert, es sei denn sie codiert Integers in umgedrehtem Zweierkomplement (-32767..32768). A. K. schrieb: > universell eindeutig ist es aber nicht Deutlicher: Es gibt C Plattformen, auf denen 1 << 15 nicht eindeutig ist. Dass es auch Plattformen gibt, bei denen es eindeutig ist, ändert daran nichts.
leo schrieb: > Wir sprachen hier von C. Ich auch. Ich beschrieb die Art, wie der C Standard denkt (ich bin mit damit leidlich vertraut). Du hingegen denkst nicht in C, sondern in "Maschine".
Gast
#5731396
A. K. schrieb: > A. K. schrieb: >> universell eindeutig ist es aber nicht > > Deutlicher: Es gibt C Plattformen, auf denen 1 << 15 nicht eindeutig > ist. Dass es auch Plattformen gibt, bei denen es eindeutig ist, ändert > daran nichts. Ich bitte um einen C-Compiler + Plattform als Beispiel. Danke, leo
leo schrieb: > Ich bitte um einen C-Compiler + Plattform als Beispiel. Es geht mir um den C Standard, nicht um reale Compiler. Ein offiziell als undefiniert festgelegtes Verhalten wird nicht dadurch definierter, dass bei realen Compilern ein nachvollziehbares Ergebnis rauskommt. Mir sind auch keine Compiler bekannt, bei denen bei einem Rechtsshift etwas anderes als das Vorzeichen reingeschoben wird. Trotzdem ist das im Standard undefiniert.
Gast
#5731416
leo schrieb: >> Deutlicher: Es gibt C Plattformen, auf denen 1 << 15 nicht eindeutig >> ist. C-Standard ist ja ok. Aber du schriebst obiges. Also noch einmal: ich bitte um ein Beispiel. Danke, leo
In irgendeinem YouTube-Video habe ich mal gehört, dass so um 1970 mal eine Architektur gab, die das Einerkomplement genutzt hat.
Heiko L. schrieb: > In irgendeinem YouTube-Video habe ich mal gehört, dass so um 1970 mal > eine Architektur gab, die das Einerkomplement genutzt hat. Beispielsweise die CDC 6600 und Nachfolger. Seymour Cray war anfangs ein Fan davon, warum auch immer. Ansonsten: "Ones-complement arithmetic: it lives!" http://esr.ibiblio.org/?p=7413
Gast
#5731440
Und wie ist es mit der Aussage:
1 | |
Ein Zweierkomplement-System: 1<<15 = 1*(2^15) (mit negativem Vorzeichen) =-32768 (dezimal) Und auf einem Einerkomplement-System: 1<<15 = 1000 0000 ..... Eine 1 am Anfang - also ist die Zahl negativ. Jetzt invertieren. 0111.....1 = 32767. Und noch das Vorzeichen: - 32767 Und -32768 != -32767 Also gilt a << #bits == a * 2^(#bits) hier auch nicht?
A. K. schrieb: > Heiko L. schrieb: >> In irgendeinem YouTube-Video habe ich mal gehört, dass so um 1970 mal >> eine Architektur gab, die das Einerkomplement genutzt hat. > > Beispielsweise die CDC 6600 und Nachfolger. Seymour Cray war anfangs ein > Fan davon, warum auch immer. > > Ansonsten: "Ones-complement arithmetic: it lives!" > http://esr.ibiblio.org/?p=7413 Na, das dürfte einen Performance-Hit geben, wenn das Zweierkomplement per Standard festgesetzt wird. Aber wer OS2200 für irgendeinen "COBOL Compatibility Layer" laufen hat kann bestimmt auch ein paar Programmierer bezahlen, die einen entsprechenden Switch in den Compiler einbauen.
zitter_ned_aso schrieb: > Also gilt > a << #bits == a * 2^(#bits) > hier auch nicht? Das kann auch noch interessanter werden, weil besagte CDC 6600 meistens mit 60 Bits rechnete, nicht aber wenn sie multiplizieren und dividieren sollte. Das machte sie nämlich nur mit 48 Bits, in der entsprechenden Fliesskomma-Einheit in Mantissenbreite. Ob es für diese jemals einen C Compiler gegeben hat weiss ich nicht. Da allerdings der Wirth'sche Pascal Referenzcompiler als grösste Integer 2^48-1 definierte, wird im Handbuch vorsorglich erwähnt, dass es auch grössere Integers als die grösste geben kann. Shift-Operationen im 1er Komplement oder sign/magnitude erklären auch, weshalb im Shifts im C Standard auf negative Werte undefiniert sind.
NB: Wer mal einen TCP/IP Stack implementiert hat, dem wird eine Einerkomplement-Addition begegnet sein. In der Checksum-Berechnung.
Ja, und, also? "Das Phantom lebt"?
Gast
#5731569
Philipp L. schrieb: > Mein Hauptprogramm zum Einlesen eines Protokolls besteht Großteils aus > Funktionen. > > while (1) > { > praemabel(); > startbit(); > Einlesen1(); > Zwischenbit(); > Einlesen2(); > > Wenn eine Funktion durchlaufen wurde, erfolgt der Rücksprung in das > Hauptprogramm und ruft dadurch die Funktion in der nächsten Zeile auf. > > Ich möchte die Funktion "Zwischenbit" nun entweder durchlaufen und > dadurch in "Einlesen2" springen, oder es erfolgt ein Sprung innerhalb > der Funktion "Zwischenbit" zurück in "praemabel". unabhängig was weiter oben steht und ob es erwähnt wurde aber für soetwas gibt es statemaschines versuch das ganze vlt als switch/case ding aufzubauen und eine einzige funktion daraus zu machen. zustandswechsel wenn alles richtig ist , sonst auf anfang oder in einen sicheren zustand. auch durchläufe zählen ( durch timeraufruf ) kann auch eine sicherheit bei "halben"/falschen protokollen erhöhen
Gast
#5731891
A. K. schrieb: > Beispielsweise die CDC 6600 und Nachfolger. Seymour Cray war anfangs ein > Fan davon, warum auch immer. Oh, darauf habe ich FORTRAN programmiert, Einer-Komplement ist mir dabei nie aufgefallen oder ich habs inzwischen vergessen. Danke, leo
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.