Hallo zusammen, irgendwo hier habe ich das schon einmal gelesen aber leider vergessen :( Und zwar wird anscheinend eine Struktur nicht wirklich Byte für Byte bei mir in den Speicher abgelegt. Es scheint so als wenn das erste unsigned char 4 bytes belegt. gab es da nicht ein zusatz den man bei einer Struct dran schreiben konnte, damit die Werte direkt hintereinander in den Speicher gelegt werden??? Ich benutze den SAM7XC256 und als Entwicklungsumgebung µVision von Keil. Ich hoffe es kann mir wer helfen. Meine Struktur ist so aufgebaut: unsigned char unsigned long int unsigned char leider ist zwischen dem ersten unsigned char und dem unsigned long int eine "lücke" von 3 Bytes. Kann man im Memorymonitor sehen :/
Sortier mal um, wenn möglich: unsigned long int unsigned char unsigned char Der versucht den "unsigned long int" auf eine glatte (durch 4 teilbare) Adresse zulegen. Ob man das auch ohne Umstellen forcieren kann, muss jemand mit mehr Ahnung beantworten ;)
Dafür hat jeder Compiler was eigenes. Beim GCC (in dessen Forum du dich ja befindest) heißt das __attribute__((packed)). Ist aber generell keine gute Idee, da es erstens unportabel ist und zweitens das Alignment ja aus gutem Grund existiert. Nicht jeder Prozessor toleriert es, wenn man Zugriffe auf 32-Bit-Daten nicht an einer 32-Bit-Grenze im Speicher ausrichtet. Manche (wie IA32) werden davon einfach nur langsamer, da sie zwei Buszyklen statt nur eines benötigen, andere wiederum verweigern dir die Arbeit und schmeißen dir einfach einen Trap, da sie gar nicht daran denken, so 'nen Quatsch erst in der Hardware ausführen zu wollen. Wenn du byteweisen Zugriff brauchst, dann bau die Struktur auch byteweise auf und schiebe dir hinterher die Multibyte-Zahlen zusammen. Was anderes könnte dir Hardware ja ohnehin nicht machen, aber damit bist du dann portabel.
Danke für die Antworten :) In der Zeit wo ihr mir geantwortet hattet, hatte ich auch das zauberwort __packed gefunden. Damit läuft es nun...nur ist leider nicht sauber da ja so ein alignment irgend nen grund hat :( "Wenn du byteweisen Zugriff brauchst, dann bau die Struktur auch byteweise auf und schiebe dir hinterher die Multibyte-Zahlen zusammen. Was anderes könnte dir Hardware ja ohnehin nicht machen, aber damit bist du dann portabel." Wie meinste das nun? Ich soll einfach nen Dickes Array speichern anstatt die Struktur? Also z.b. nen Array von 6 Bytes und zerstückel es dann selber in die einzelnen Variablen? Bei dem Zugriff läuft das bei mir so ab: Ich kriege ein Wert, einen Subindex, entweder 0,1 oder 2 und der sagt mir welche der Variablen ich lesen oder schreiben will und dann setze ich ein Pointer auf die Adresse von der Struktur und wenn ich Wert 0 will gebe ich ihn zurück, wenn ich Wert 1 will rechne ich den Pointer++ und gebe den Wert zurück und bei Wert 2 rechne ich den Pointer+5 und gebe den Wert zurück. Ansich würde das auch gehen wenn ich das ganze nicht in Strukturen speicehre sondern in Arrays...aber das sieht dann total unsauber aus :( An anderen Stellen des Programmes greife ich direkt auf den Wert in der Mitte der Struktur zu. Darum wäre die Möglichkeit alles in nem Array zu speichern eigentlich nicht so schön.
Woher kommt denn deine Anforderung nach dem Auslassen der Füllbytes? Wenn das irgendwo durch Hardware bedingt ist bzw. externe Kommunikation, dann ist das Array sicher die sinnvollste Lösung.
"...nach dem auslassen der füllbytes?" hm??? Also ich will die Füllbytes auslassen weil ich den Pointer nur um eins erhöhen will. Theoretisch könnte ich auch den Pointer, wenn ich Wert2 lesen will, um 5 erhöhen anstatt nur um 1, aber das wäre ja auch getrickst. Verändert sich das alginment wenn ich ne andere Optimierung wähle? Da das ausserdem ein Array von 128 dieser Strukturen betrifft, ist das doch ne riesen speicherverschwendung wenn ich das nicht packe. Das ganze ist beim CANopen Protokoll, und zwar kriege ich per CAN Telegramm eine Objektnummer, die ich beschreiben oder lesen will. dann gucke ich in dem ersten Array, welche Variable zu der Nummergehoert und habe die Pointeradresse dadrauf. Wenn man nun SUbindex 1 lesen/schreiben will dann heißt das man möchte den zweiten Wert der Struktur(die von oben) lesen/schreiben. Der Pointer ist vom Type unsigned chjar und kann auch nicht ein pointer vom typ der struktur sein, weil er noch andere Werte lesen muss. An anderen Stellen im Programm schreibe ich aber auch direkt bzw. lese sehr oft die mittlere Variable der Strukur aus. Darum wäre es sehr umständlich wenn ich dort immer erst den WErt aus einem Array zusammen setzen müsste. Gibt es eine möglichkeit zu erkennen, das dort ein alginment vorgenommen wurde? Was mir auch sagt wieviele Bytes hinzugefügt wurden? Bestimmt nicht oder? Die Strukturelemente zu tauschen würde nun ein riesen aufwand bedeuten aber falls das dann klappen würde wäre es ne Möglichkeit.
Warum greifst Du mit einem char-Pointer auf Strukturelemente anderen Typs zu? Wenn Du das tust, kannst Du auch gleich mit char-Arrays arbeiten und Dir den Aufwand der Strukturdefinition sparen.
>Damit läuft es nun...nur ist leider nicht sauber da ja so ein alignment >irgend nen grund hat :( Überlass das doch einfach dem Compiler. Solange das Programm macht, was du willst, und das auch schnell genug ist, brauchst du dir darüber nicht den Kopf zu zerbrechen. Oliver
Warum ich ein Char Pointer nehme? Weil ich Byteweise die Daten sende und Byte für Byte von verschiedenen Variablentypen lese. Mal ist es eine Variable aus der Struktur, mal ein Integer und manchmal nur ein Charakter oder irgendwas anderes. Warum es kein Array sein kann? Weil ich in einem anderen Interrupt direkt nur auf den zweiten Wert der Struktur zugreife. Dort die Byteausleserei aus einem Array wäre zuviel Aufwand. Das Problem mit dem Pack war nun die Performance :( Mein Interrupt brauchte nun 20µs länger als vorher also anstatt 46µs nun 67µs. Das war nun zu lange. Also habe ich es anders gelöst. Etwas umständlich aber es klappt. Ich habe nun noch ein zweiten Pointer vom Typ der Struktur der dann auf das jeweilige Element der Struktur zeigt und diese Adresse gebe ich dem anderen Charakter Pointer. Danke für eure Hilfreichen Kommentare. Gruß Jens
> "...nach dem auslassen der füllbytes?" hm??? > > Also ich will die Füllbytes auslassen weil ich den Pointer nur um eins > erhöhen will. Theoretisch könnte ich auch den Pointer, wenn ich Wert2 > lesen will, um 5 erhöhen anstatt nur um 1, aber das wäre ja auch > getrickst. Die Frage nochmal anders formuliert: Warum dürfen keine Füllbytes vorkommen? > Verändert sich das alginment wenn ich ne andere Optimierung wähle? Beim normalen -O* würde ich das nicht erwarten, da man in der Regel Code zusammenlinken kann, wo diese Einstellung verschieden ist, also muß das ABI kompatibel sein. Aber es gibt ja noch andere Optimierungs-Optionen, bei denen das evtl. anders ist. Es ist halt auch prozessorabhängig. > Da das ausserdem ein Array von 128 dieser Strukturen betrifft, ist das > doch ne riesen speicherverschwendung wenn ich das nicht packe. Naja, kommt auf die Speicherkapazität an. 128*6 = 768 Bytes wäre der Overhead. Du mußt aber auch rechnen, daß bei einer Architektur, die Zugriffe mit falschem Alignment nicht unterstützt, zusätzlicher Code geschrieben werden muß, der ja auch Platz braucht und dazu noch bei jedem Zugriff Performance schluckt. Wenn du deine Struktur so umsortieren kannst, daß die unsigned char alle am Ende stehen, wäre der Overhead nur 2 statt 6 Bytes. > dann gucke ich in dem ersten Array, welche Variable zu der > Nummergehoert und habe die Pointeradresse dadrauf. Wenn man nun > SUbindex 1 lesen/schreiben will dann heißt das man möchte den zweiten > Wert der Struktur(die von oben) lesen/schreiben. Verstehe ich noch nicht ganz. Ist der Subindex nun ein Byte-Offset innerhalb der Struktur oder die Nummer des Elements? > An anderen Stellen im Programm schreibe ich aber auch direkt bzw. lese > sehr oft die mittlere Variable der Strukur aus. Darum wäre es sehr > umständlich wenn ich dort immer erst den WErt aus einem Array zusammen > setzen müsste. Wenn dein Prozessor ein 32-Bit-Alignment dafür benötigt, wäre es noch viel umständlicher, wenn du jedesmal immer erst das Struct-Element in ein Array umkopieren und dann daraus deinen Wert zusammensetzen müßtest. > Gibt es eine möglichkeit zu erkennen, das dort ein alginment > vorgenommen wurde? Was mir auch sagt wieviele Bytes hinzugefügt wurden? > Bestimmt nicht oder? Du kannst offsetof verwenden, um die Position eines Elements innerhalb einer Struct zu ermitteln. Daraus kannst du dir die Füllbytes ausrechnen. Aber generisch geht das natürlich nicht. Du mußt dem offsetof immer den Namen der Struktur und des Elements übergeben. > Die Strukturelemente zu tauschen würde nun ein riesen aufwand bedeuten Warum?
Der Subindex ist die Nummer des Strukturelements: Subindex 0: erste Strukturelement unsigned char Subindex 1: zweite Strukturelement unsigned long int Subindex 2: dritte Strukturelement unsigned char Die Struktur zu tauschen wäre nen riesen aufwand weil ich mein riesen Array umschreiben muss. Das ist ja schon mit Defaultwerten gefüllt. Also wenn ich das dingen Packe geht mir einfach zuviel Performance verloren da ich ja sehr schnell zugreifen muss. Die möglichkeit nun mit dem Zweiten Pointer erscheint mir die beste. Ich werde nun aber doch noch einmal Testen ob ich die Struktur umschreibe so das die unsigend char am ende sind und ich damit weniger Overhead kriege.
> Der Subindex ist die Nummer des Strukturelements: Gut, das heißt aber dann, daß du in der Software noch irgendwo eine Tabelle haben mußt, wo die Zuordnung zwischen Nummer und Offset steht. Wenn die genannte Struktur gepackt wäre, wären die Adressen ja so verteilt: > Subindex 0: erste Strukturelement unsigned char @ Struct-Anfang > Subindex 1: zweite Strukturelement unsigned long int @ Struct-Anfang + 1 > Subindex 2: dritte Strukturelement unsigned char @ Struct-Anfang + 5 Wenn du so eine Tabelle hast, wäre es doch völlig problemlos möglich, die Elemente der Struktur zu tauschen und dann einfach die Offsets in der Tabelle anzupassen. > Die Struktur zu tauschen wäre nen riesen aufwand weil ich mein riesen > Array umschreiben muss. Das ist ja schon mit Defaultwerten gefüllt. Ach so. In C gibt's eine Syntax, mit der das kein Problem wäre. Vielleicht eine Überlegung für nächstes Mal:
1 | struct Blah |
2 | {
|
3 | int a; |
4 | int b; |
5 | int c; |
6 | };
|
7 | |
8 | struct Blah foo = { .a = 3, |
9 | .b = 5, |
10 | .c = 2 }; |
Die Reihenfolge der Elemente spielt hier keine Rolle mehr, sondern nur noch deren Namen.
Hey Danke für den Tip mit der andere deklarationssyntax. Die kannte ich noch nicht. Das macht die Sache natürlich echt praktisch. Durch meine jetzige Lösung ist es ja auch egal an welcher Stelle die Variable steht so das ich garkeine Offsets mehr berechnen muss. Verkürzt sieht das nun so aus:
1 | pucStrukturPointer = (Structur1 *)pucCharakterPointer; |
2 | switch(Subindex) |
3 | {
|
4 | case 0: |
5 | pucCharakterPointer = (unsigned char *) &pucStrukturPointer->Wert1; |
6 | break; |
7 | |
8 | usw... |
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.