Hallo Zusammen,
ich bin gerade an einer Aufgabe hängengeblieben welche ich nicht verstehe.
Es geht um eine Ampelsteuerung.
Kann mir jemand erklären wie dass funktioniert? :D
Bild im Anhang.
Vielen Dank schonmal
Grüße Robin
|
Anzeige
|
Aufgabe Ampelsteuerung StudiumHallo Zusammen, ich bin gerade an einer Aufgabe hängengeblieben welche ich nicht verstehe. Es geht um eine Ampelsteuerung. Kann mir jemand erklären wie dass funktioniert? :D Bild im Anhang. Vielen Dank schonmal Grüße Robin
Dein Professor bzw. deine Lehr-Unterlagen? Die Aussage "beginnt immer mit dem LSB" ist nicht allgemeingültig richtig (der C-Standard macht dazu nämlich keine Festlegung), aber für den Kontext der Aufgabe natürlich wichtig: ganz oben im Text steht das niederwertigste Bit, LSB (least significant bit), das hat den Zahlenwert 1. Das nächste bit hat dann den Zahlenwert 2 usw. Für den Rest schau bitte nochmal in deine Unterlagen. Haaaaalt Stop! Soll das heißen das ich in einem struct schon quasi bitweise arbeiten kann?! o.O Warum lege ich dann immer Bytes an und mach Schiebeoperationen darauf?! Seit wann ist das so? Und warum hat mir das noch nie irgendjemand mal gesagt! Ehrlich jetzt. :-D Oh man ey!
Gast
#7330246
Als ob man nicht schnell im Compiler nachprüfen könnte Soll das C oder C++ sein? Hier ist die gesamte Problemstellung dargestellt:
Das ist eine Sonderform eines struct, die heißt bitfield. Und ja, die heißt deshalb so, weil man damit bitweise arbeiten kann.
Weil so ziemlich alles an bitfields "implementation defined" ist, d.h. entsprechender Code ist nicht portabel. Ob
daher in anzeige.ausgangsbelegung die Zahl 0x10 oder 0x02 hinterlässt, kann man nicht garantieren. Für die Aufgabenstellung garantiert das die Anmerkung, dass das LSB zuerst kommt, das erklärt gewissermaßen den tatsächlichen Status des "implementation defined" für die angenommene Implementierung.
Kann ich nicht genau nachvollziehen, war aber mindestens seit der ersten Auflage des "K&R" ("The C programming language") im Jahr 1978 dabei: Vielen Dank Leute. Hab es schon verstanden :D
Ja. Tatsächlich wird der Compiler das dann für dich entsprechend übersetzen. Der Maschinencode wird identisch zu deinen von Hand geshifteten Bits. ABER: Das funktioniert unter einer bestimmten Architektur mit einem bestimmten Compiler. C/C++ garantiert dir nicht das exakte Memory-Layout bei einem struct. Implementierungsabhängig könnte der Compiler die 6 bits auch auf 6 Bytes verteilen. Du arbeitest auf der struct-Abstraktion, um das tatsächliche Layout kümmert sich der Compiler. In der Praxis funktioniert das aber. Zumindest so lange man Compiler oder Architektur nicht wechselt. Genauso der wechselseitige Zugriff auf die beiden Union-Teile. Union sagt, dass die sich den Speicher teilen. Aber nicht wie. Genaugenommen ist es Undefined Behaviour, zuerst die einzelnen Bits zu setzen und dann über den union-member ausgangsbelegung auszulesen oder andersrum. Standardkonform ist ausgangsbelegung nur dann definiert, wenn du vorher ausgangsbelegung beschrieben hast. In der Praxis funktioniert das aber. Wichtig ist, dass man solche Tricks auf die Stellen begrenzt, wo es unbedingt notwendig ist. Z.B. um besser auf einzelne Bits eines Hardware-Registers zugreifen zu können. In Header-Files von Mikrocontrollern findet man sowas z.B. relativ häufig. In generischem, nicht hardwarenahem Code hat sowas meiner Meinung nach nichts zu suchen! Undefined Behaviour hat die "großartige" Eigenschaft, zumindest theoretisch irgendwann in bestehendem, unverändertem und gut getestetem Code Fehler zu erzeugen. Einfach weil in 20 Jahren ein Compiler vielleicht mal auf die Idee kommt, irgendwas, was gemäß Standard ohnehin nicht vorkommen sollte, anders zu interpretieren. Edit: Jörg war schneller... Okay Jungs! Danke für eure Aufklärung. Also bleibe ich mal beim Bits schieben. :-) Aber interessant das es so etwas gibt.
Ist das hier aber nicht. Das ist "implementation defined", d.h. eine konkrete Implementierung muss dir auch dokumentieren, wie sie es umgesetzt hat. Ist wirklich eine ganz andere nummer als "undefined", denn da kann dir alles mögliche passieren (bis hin zum kompletten Ignorieren von Code, der scheinbar gar nichts damit zu tun hat).
In C++ ist das UB (Lesen des non-active members). In C ist dies ok. Die Festlegung über das LSB ändert IB hier jedoch nicht zu well-defined. Die anderen Bitpositionen bleiben IB.
OK, da wir aber von einer Ampelsteuerung und einer Studienaufgabe sprechen, würde ich eh erstmal nicht von C++ ausgehen. Offenbar geht's ja hier um die Grundlagen von C, und das "Lesen" von .ausgangsbelegung war wohl eher die Frage, dass die Studenten ein Verständnis dafür entwickeln, was in der Maschine passiert, wenn man ein Bitfield ändert. (Aber akzeptiert, ich hatte Tilos Antwort nicht zu 100 % gelesen zu nächtlicher Stunde und dadurch den Teil verpasst, dass er auch auf die beiden union member eingegangen ist.)
Gast
#7330701
Warum kann man den 10-Zeiler aus der Aufgabenstellung nicht einfach mal selbst kompilieren, und dann sehen was passiert. Vielleicht selber mal mit den Bits und Bytes spielen, und sich die entstehenden Muster anschauen. 15 Minuten zuhause probiert, und mehr gelernt als aus den Antworten hier im Forum. Ein Tipp: mit printf() kann man sich Variablen anzeigen lassen.
Selbst wenn wir hier von C ausgehen (kein UB sofern kein strict-aliasing verletzt wird), hat man IB und man lernt nicht das, was der Aufgabenersteller lehren wollte.
Doch, denn die Implementierung hat er in der Aufgabenstellung mit definiert. Leute, macht aus ein bissel Bitschubsen für Anfänger doch keine Raketenwissenschaft. Um überhaupt erst einmal Bitfelder zu verstehen, hat die Aufgabe ganz offensichtlich (wie uns der TE bestätigt) genügt. Dass das Ganze zumindest unportabel ist, sollte dabei gleich auch mit klar geworden sein.
Gast
#7330877
Muss man noch nicht mal zu Hause ausprobieren:
Nein, hat er nicht: lediglich LSB. Sonst nichts. Das fängt schon damit an, dass die Basistypen für die Bitfeld-Elemente nicht (unsigned) int sind. Das ist an sich schon IB. Dann fehlt die Festlegung, dass hier gelten soll, dass alle Bitfeld-Elemente gepackt liegen sollen. Alles nicht angegeben.
Das mache ich nicht, jedoch sollte man gerade dem Anfänger nicht auf die falsche Fährte führen (und schon gar nicht als Lehrer). Gerade weil es für den Anfänger ggf. schwierig zu verstehen ist, was UB oder IB oder aliasing oder all die anderen Freiheitsgerade eines Compilers in C/C++ sind.
Offensichtlich hat der Aufgabensteller die eigentliche Problematik gar nicht verstanden. Sonst hätte er die Aufgabe so nicht gestellt. Denn Bitfelder als Abstraktion von HW-Registern zu verwenden ist einfach nur falsch.
Das hoffe ich doch, hoffentlich auch dem Aufgabensteller.
Wofür ist das hier relevant?
Ist automatisch, denn alle haben nur die Länge 1. Zumindest im C-Standard darf es dann gar kein Padding geben. (Würde mich wundern, wenn C++ das gestattet.)
Wird aber oft gemacht, bspw. findest du in ganz vielen ARM-Headern sowas. Beispiel gefällig?
Aus core_cm4.h.
Gast
#7332966
Was verstehst du an der Aufgabe nicht? Die Kommentare bei der Deklaration geben dir den entscheidenden Hinweis und die Lösungen stehen sogar schon dabei.
Dass du irgendwie drei Tage zu spät gekommen bist für deine großartige Frage?
Das ist leider in der Allgemeinheit falsch, allerdings ist es in diesem Spezialfall m.E. in C richtig (nicht in C++): die Bit-Felder werden in einer sog. addressable-storage-unit (ASU) untergebracht. Diese muss nur so groß sein, wie das Bit-Feld, und nicht wie angegeben. Ob angrenzende ASU ohne padding allokiert werden, ist unspezifiziert. In dem speziellen Fall dieser Aufgabe werden 1-Bit Bit-Felder deklariert. Die kleinste dafür mögliche ASU wäre 1-Byte. Da aber nur 6 Bit-Felder deklariert werden, sollten die dann alle in dieser ASU ohne padding untergebracht werden. Also: in dieser speziellen Aufgabe dann wohl kein padding.
Weiß ich , macht es aber nicht besser ;-)
Hier wäre also möglich, dass für das Bit-Feld ISR eine ASU mit 16-Bit benutzt wird. Mit dem folgenden reserved0 ist dann diese ASU voll. Die nä. ASU für GE kann dann einfach nur 1 Byte sein. Zwischen diesen ASUs darf beliebig padding eingebaut werden (ja. ich weiß, das macht sicher kein ernst zu nehmender Compiler, doch darim geht es ja in diesem Moment nicht, wir sind in der Position des language-lawyers). Dann folgt reserved1, damit wäre dann die zweite ASU voll. Dann beginnt die nä. ASU mit wieder beliebig padding zur zweiten ASU. Die Größe und das Alignment der ASUs ist unspezifiziert (nicht implementaion-defined). Wie man sieht ist also auch in C dieses Konstrukt leider eigentlich unbrauchbar ist. Es sei denn, man beschränkt es auf eine bestimmte Compiler-Art/Version. Das sehe ich aber in den typischen CMSIS-Headern nicht. BTW: in C++ hätte man überhaupt keine Chance, also es wäre alles implementation-defined. Aber es wäre auch UB, weil man entsprechend der Aufgabenstellung gezwungen wäre, auf das nicht-aktive Element der Union zuzugreifen...
Beitrag #7335542 wurde von einem Moderator gelöscht.
Antwort schreibenBitte melde dich an, um einen Beitrag zu schreiben. |
Anzeige
|