Hallo zusammen, ich bin gerade bei meiner Bachelor Arbeit und muss eine bestehende Software auf einem Keil Board zum laufen bringen (fürs erste). Funktioniert auch alles bisher ganz gut. Das Board ist ein MCB2140 (LPC2148) von Keil und Bestandteil des hitex StarterKits. Jetzt ist es so, dass ich in dem Programm ( C ) auf dem Controller von einer Funktion ein Struct zurückbekommen sollte. Bekomm ich aber nicht, sondern nur den ersten Teil dieses structs. Das aber nur so nebenbei. Mein Chef meinte, das alles liegt am alignement des Prozessors. Habe mich jetzt auch ein wenig eingelsen, was alignement angeht und weiss jetzt schonmal was das ist :) Jetzt muss ich rausfinden wie das alignment auf dem Stack ist und mit dem vergleichen, für den dieses Programm urspürnglich geschrieben wurde. Weiss vielleicht jemand wie das bei dem ARM7 Prozessor ist? Grüße Nils
Bitte mehr Infos: Welcher Compiler, welche Optimierung (-O), relevante Quelltextausschnitte, Testläufe
Sorry, leider bin ich ganz neu im C Geschäfft, aber ich versuche mal so viel ich weiss zu beantworten. Da fällt mir aber gerade auf, dass ich nur den Compiler kenne: arm-hitex-elf-gcc. Vielleicht würde es mir schon helfen, wenn jemand weiss, wie das alignment des LPC2148 ist, dann kann ich weiter googlen.
OK jetzt hab ich was: typedef struct { UInt uiLength; /* Current length of flex string */ Char charData[8]; /* Content of string */ } FlexString8; typedef struct { FlexString8 Name; FlexString4 Version; } DeviceIdent_Struct; USInt usiOffset1 = offsetof ( DeviceIdent_Struct, Version ); // 0x0C USInt usiOffset2 = offsetof ( FlexString8, charData ); // 0x02 USInt usiOffset3 = sizeof(FlexString8); // 0x0C USInt usiOffset4 = sizeof(UInt); // 0x02 USInt usiOffset5 = sizeof(Char); // 0x01 USInt usiOffset6 = sizeof(Char[8]); // 0x08 Nur weiss ich jetzt zb.B. leider nicht, wie die sizeOf( FlexString) zustande kommt. Eigentlich müsste die doch 10 sein und nicht 12. Liegt das am Alignment des Controllers? Unter welchen Umständen schmeisst der mir noch 2 "Füllbytes" in die Länge mit rein? Grü0e Nils
Der Compiler macht da wohl ein Word-Alignment. In dem Fall ist die Lücke zwischen uiLength und charData. Versuche es doch mal damit: typedef struct { UInt uiLength; /* Current length of flex string */ Char charData[8]; /* Content of string */ } __attribute__((packed)) FlexString8; Wobei ich nicht weiß inwieweit der Arm7 das unterstützt. Der Zugriff auf Daten im Speicher ist bei manchen Prozessoren schneller wenn diese (Daten) an Wortgrenzen ausgerichtet sind. - Michael
hallo nils, ja der arm benötigt ein alignment, abhängig von der größe der variable auf die er zugreifen soll. 16 bit variable (im arm jargon "half word") müssen auf durch 2 teilbare adressen beginnen. 32 bit variable (im arm jargon "word") müssen auf durch 4 teilbare adressen beginnen. dies weiss der compiler natürlich und füllt deine struktuiren entsprechend auf. kritisch istr bei manchen compilern aber der sizeof operatir da dieser ev. die füll-bytes nicht berücksichtigt. ich würde dir empfehlen das auffüllen selbst zu machen und die strukturen entsprechend zu definieren. gruss gerhard
Schonmal vielen Dank, das _attribute_ ((packed)) hat leider nicht geholfen, die Länge meines FlexStrings ist immer noch 12. #pragma pack(1) hab ich auch versuch, ging auch nicht. Aber wo packt der denn seine Füllbytes bei dem FlexString rein? Wenn USInt usiOffset2 = offsetof ( FlexString8, charData ); gleich 2 ist, dann müsste er sie doch hinter die charData einbauen oder?
Stümmt, darauf habe ich nicht geachtet. Das 'packed' bringt dann so oder so nichts. Vom Padding am Ende einer Struktur habe ich noch nie gehört. Ich habe seit zwei Tagen ein 2148 Board. Der UART geht inzwischen, sodaß ich das mal mit meiner GCC Version (4.1.1) probieren kann. Geht aber erst heute Abend. - Michael
Möglicherweise hilft das packed-attribute schon - aber nur teilweise. Wenn recht erinnert, wird vom gnu C-Compiler dann auch das character-array "unmittelbar" hinter dem Längen-Integer angeordnet aber am Ende wieder auf "grade" Wordadresse aufgefüllt. #pragma pack dürfte das Gleiche auslösen (ich habe pragmas bei gcc noch nie genutzt). In der "untersten Ebene" für Flexstring würde attribute packed dann hilfreich sein, aber eine Ebene drüber bei DeviceIdent nicht mehr. Das Ganze entspricht ja den bisherigen Erkenntnissen. Lässt sich aber auch gut testen, in dem man einen uint8_t* auf die Startadresse eines Objekts der Struktur zeigen lässt ("casten") und dann Byte für Byte ausgibt "cout(*p++)" (oder per Debugger anschaut), dann Elemente ändern und wieder Bytestream anschauen. Der tatsächliche Offset wird dann gut erkennbar. Aber diese Art der Zugriffs auf Elemente ist nicht wirklich gut, insbesondere wenn aligments zur Optimierung des Speicherzugriffs im Spiel sind. Man läd sich - wie schon gemerkt - neue Sorgen auf. Besser wäre es Code zu schreiben, der die einzelnen Elemente eines Objekts aus der Struktur in ein Bytearray schreibt, bzw. aus einem Bytearray den Inhalt für die Elemente ausliest (Serializer/Deserializer). Vielleicht etwas langsamer aber dafür problemloser.
Bist Du eigentlich sicher, daß UInt 2 Bytes groß ist? Ein unsigned int sollte auf einem ARM eigentlich 32 Bit groß sein. Was genau ist UInt bei dir? Um einigermaßen portabel zu sein könnte man auch die Typen uint8_t, uint16_t und uint32_t aus stdint.h verwenden. Zum Thema Attribute http://gcc.gnu.org/onlinedocs/gcc-4.1.1/gcc/Type-Attributes.html#Type-Attributes
Zumal es idR weder aus Speicherverbrauchs- noch aus Performance-Sicht dienlich ist, auf einem ARM Integers mit weniger als 32 bit zu verwenden. Alternative: Das Uint an das Ende der Struktur, falls es wirklich nur zwei Bytes hat.
So, ich habe mal den GNUARM Compiler v4.1.1 angeworfen: typedef struct { char a; // 1 Byte int b; // 4 Bytes short c; // 2 Bytes char str[8]; // 8 Bytes } testObj; Ergebnis: sizeof(testObj) = 20 offsetof(a) = 0 offsetof(b) = 4 offsetof(c) = 8 offsetof(str) = 10 Und: typedef struct { char a; // 1 Byte int b; // 4 Bytes short c; // 2 Bytes char str[8]; // 8 Bytes } __attribute__((packed)) testObj; mit dem Ergebnis: sizeof(testObj) = 15 offsetof(a) = 0 offsetof(b) = 1 offsetof(c) = 5 offsetof(str) = 7 Der ARM7 ist also offenbar nicht auf ein Alignment angewiesen, auch wenn es schneller sein mag. Wo die zwei Bytes am Ende der "von Nils'schen" Struktur herkommen kann ich mir nicht erklären. Da 'UInt' anscheinend nur zwei Bytes groß ist, handelt es sich bei der Struktur wohl um eine Schnittstelle für Daten die von Außen angeliefert werden. Stimmts ? ;) - Michael
Der ARM7 ist sehr wohl auf Alignment angewiesen. Ein 32bit-Load mit A0:1 !=0 wird zwar nicht auf die Nase fallen, aber auch nicht das tun, was man davon vielleicht erwartet. Nur erzeugt der Compiler in solchen Fällen Code, der auch ohne Alignment auskommt. Bei Bitfields geht es ja auch.
^ Ich dachte mir schon das meine Aussage etwas voreilig war und habe mir mal die .lst-Datei angesehen. Der Compiler schiebt die Daten in der Tat passend zurecht. Der GCC beeindruckt mich immer wieder. Ich mußte die Codeoptimierung abschalten damit auch tatsächlich auf 'obj' zugegriffen wird. Sonst hat der Compiler für rprintf() einfach die Konstanten eingesetzt:
1 | typedef struct { |
2 | char a; |
3 | char b; |
4 | char c; |
5 | short size; |
6 | } __attribute__((packed)) stype; |
7 | |
8 | obj.a = 1; |
9 | obj.b = 2; |
10 | obj.c = 3; |
11 | obj.size = sizeof(stype); |
12 | |
13 | rprintf("a=%u, b=%u, c=%u, size=%u\n", obj.a, obj.b, obj.c, obj.size); |
- Michael
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.