hallo, ich hab wider mal ein Problem. Theoretisch könnte ich es auch mit einem Struct lösen, allerdings würde es sich so bloss noch mehr verkomplizieren. Also ich möchte aus 4 byte die in einem 512 byte array stecken einen Integer machen(VolumeBootRecord einer sd karte ist in dem Buffer) nun hab ichs mal so versucht: root_dir_first_cluster = (unsigned int)buffer[BPB_RootClus]; ich dachte der Gcc wäre klug genug sich dann nicht nur das erste byte, sondern auch die 3 darauf folgenden zu holen... Shiften mit den einzelnen Bytes ginge auch, macht das ganze aber unübersichtlicher. Gibt's vielleicht nicht doch eine einfachere Lösung als ein Struct oder Shiften? mfg Nik
1. vier bytes ergeben auf einem AVR ein unsigned long. 2. root_dir_first_cluster = *((unsigned long)&buffer[BPB_RootClus]); ;)
Sorry... 2. root_dir_first_cluster = *((unsigned long *)&buffer[BPB_RootClus]);
...und der GCC hat genau das getan was Du ihm aufgetragen hast. "root_dir_first_cluster = (unsigned int)buffer[BPB_RootClus];" Hole das byte das im Speicherbereich mit dem Namen buffer bei offset BPB_RootClus steht, mache ein unsigned integer daraus und weise den Wert der Variablen root_dir_first_cluster zu. "root_dir_first_cluster = *((unsigned long *)&buffer[BPB_RootClus]);" -> Hole die Adresse der Speicherstelle die bei buffer + BPB_RootClus steht, wandle diese Adresse ins einen zeiger auf einen unsigned long im und weise dessen Inhalt der ... Der Compiler übernimmt das Optimieren ;) Wirklich Elegant wird der Code aber nur mit struct. Werner
Wow vielen Dank, klappt echt hervorragend :D Also wenn ich das mit dem Struct verstanden habe, dann müsste ich im Prinzip ja den Ganzen inhalt von buffer irgendwie einer Variable zuweisen. Ich kann dann ja nicht nur z.B. die bytes 8-12 und 400-404 'rausholen' sondern ich muss auch den ganzen platz dazwischen zuweisen, somit würde ich ja dann zusätzlich zum Buffer nochmals 512 byte ram brauchen.(?) Falls das nicht der Fall ist werde ichs natürlich gerne mit einem Struct machen, aber ich brauch sowiso nur zwei solch nichtelegante Umformungen wie sie du mir nun erklärt hast :) Aber da mein restlicher code sowiso nicht vor Eleganz prozt... Nik
> Also wenn ich das mit dem Struct verstanden habe, dann müsste ich im > Prinzip ja den Ganzen inhalt von buffer irgendwie einer Variable > zuweisen. Ich kann dann ja nicht nur z.B. die bytes 8-12 und 400-404 > 'rausholen' sondern ich muss auch den ganzen platz dazwischen > zuweisen, somit würde ich ja dann zusätzlich zum Buffer nochmals > 512 byte ram brauchen.(?) Quatsch. Du definierst Dir eine struct die dem Speicher-Layout der Daten entspricht. Dann definierst Du dir einen Pointer auf so eine struct. Dem Pointer weist Du als Wert die Adresse zu, wo die Daten im Speicher tatsaechlich stehen. Und schon kannst Du ueber den Pointer auf die Daten zugreifen wie Du lustig bist. Im Grunde erklaerst Du einfach nur dem Compiler wie der Daten- aufbau im Speicher aussieht (daher die struct). Dann sagst Du dem Compiler: Siehst Du so sieht das Ding aus (die struct) und genau dort im Speicher ist so ein Trum (der Pointer zeigt dorthin). Das hat genau den Aufbau der durch die Struct beschrieben ist. Also mach mal, ich will Zugriff auf die-und-die Komponente.
Hallo, nach ein wenig suchen, habe ich diesen Eintrag hier gefunden, der genau das beschreibt, was bei mir Probleme macht. Ich versuche gerade den uIP TCP/IP-Stack auf einem Olimex LPC-L2294 Board zu implementieren. uIP verwendet genau oben beschriebenes Vorgehen wie folgt. Es gibt den Buffer (1 Byte Breite) welcher die empfangenen oder zu sendenden Pakete enthält. u8_t uip_buf[1500]; Weiterhin gibt es die Strukturen struct uip_eth_addr { u8_t addr[6]; }; und struct uip_eth_hdr { struct uip_eth_addr dest; struct uip_eth_addr src; u16_t type; }; und einen Zeiger vom Typ letzterer Struktur welcher auf den Anfang des Buffers zeigt #define BUF ((struct uip_eth_hdr *)&uip_buf[0]) Kommt jetzt ein ARP-Request rein, so speichert mein Devicetreiber das Paket korrekt im Buffer ab. D.h. die ersten 6 Byte werden durch die Broadcast MAC-Adresse belegt, die nächsten 6 Byte durch die Sender MAC-Adresse, und die Bytes mit dem Indexen 12 und 13 enthalten den Typ der Nachricht, also in dem Fall steht in uip_buf[12] = 0x08 und in uip_buf[13] = 0x06. In der Mainloop soll nun mittels BUF->type auf diesen Typ zugegriffen werden. Das heißt, es wäre zu erwarten, dass in BUF->type = 0x0608 (little endian) steht, da type ja eine Breite von 2 Byte hat. Ich habe diese Codeteile in ein devc++ C-Projekt eingefügt, und auf dem Rechner getestet, hier funktioniert dies wie erwartet. Lade ich das Programm auf das MC-Board, stelle ich beim debuggen fest, dass in BUF->type lediglich 0x08 drin steht, was zu Folge hat, dass der Nachrichtentyp nie richtig erkannt wird. Ich verwende die Yagarto Toolchain mit dem gcc Compiler und Eclipse als Oberfläche. Kann mir jemand erklären, wo hier das Problem liegt? Sorry, wenn ich nötige Angaben vergessen haben sollte, die poste ich natürlich auf Anfrage gleich nach! Viele Grüße, Norman
Hallo, aber in einer union würden doch alle Variablen auf die gleiche Adresse zeigen. Ich brauche aber die Inhalte der aufeinanderfolgenden Speicherbereich im Buffer. Oder wie ist das gemeint mit dem union. Eigentlich möchte ich den Code von uIP auch nicht ändern. Denn der müsste ja so auch funktionieren. Es gibt sogar ein Beispielprogramm bei Olimex, für dieses Board, welches diesen Code genauso anwendet. Nur irgendwie funktioniert es nicht so, wie erwartet. Mich würde interessieren, wo hier das Problem liegen könnte. Gruß, Norman
Norman Meier wrote:
> Kann mir jemand erklären, wo hier das Problem liegt?
Ich schätze mal, dein Problem besteht im Padding.
Der Compiler kann in eine struct zwischen die einzelnen
Member zusätzliche Bytes einfügen um dadurch gewisse Restriktionen
der Hardware zu erfüllen. Compiler machen das gerne um die
einzelnen Member auf zb geradzahlige Adressen oder Adressen die
durch 4 teilbar sind zu bekommen.
-> Handbuch deines Compilers studieren, wie du das Padding für
eine struct abschalten kannst. Oft ist das ein #pragma
Norman Meier wrote:
> Oder wie ist das gemeint mit dem union.
Ich schätze mal Norgan meinte:
union {
u8_t uip_buf[1500];
struct uip_eth_hdr hdr;
}
und Zugriffe dann über die Union führen.
Ich bezweifle aber, dass das dein Problem lösen wird.
1 | #define BSIZE (512) // Puffergroesse in bytes
|
2 | #define F (4) // Groessenfaktor
|
3 | #define LSIZE (BSIZE / F) // Puffergroesse in long
|
4 | |
5 | typedef union { |
6 | uint8_t b[F]; |
7 | uint32_t l; |
8 | } Element; |
9 | |
10 | Element buffer[LSIZE]; // 512 bytes, 128 long |
11 | uint32_t l; |
12 | |
13 | // Bytes in Puffer schreiben
|
14 | int i, j; |
15 | for(i = 0; i < LSIZE; i++) { |
16 | for(j = 0; j < F; j++) { |
17 | buffer[i].b[j] = get_byte_data_from_somewhere(i * F + j); |
18 | }
|
19 | }
|
20 | |
21 | // oder
|
22 | for(i = 0; i < BSIZE; i++) { |
23 | buffer[i / F].b[i % F] = get_byte_data_from_somewhere(i); |
24 | }
|
25 | }
|
26 | |
27 | |
28 | // long aus Puffer lesen
|
29 | for(i = 0; i < LSIZE; i++) { |
30 | l = buffer[i].l; |
31 | }
|
Hey, vielen Dank! Das Padding ist offensichtich das Problem. Habe mir gerade mal die größe der Struktur anzeigen lassen. Das ergibt 18, statt 14. Da ausgerecht an dieser Stelle im Ethernetpaket 0x0800 drin steht, habe ich nicht gemerkt, dass ich eigentlich auf eine andere Adresse zugreife. Jetzt muss ich das Padding nur noch wegbekommen. Vielen Dank auch an Norgan für die Hilfe! Gruß, Norman
> Jetzt muss ich das Padding nur noch wegbekommen.
Das sollte eigentlich mit
1 | __attribute__ ((packed)) |
funktionieren.
Hey Danke, habe es so hinbekommen. Allerdings war der Compiler ganz schön gierig. Musste das _attribute_ ((packed)) teilweise vor und nach den Strukturen angeben und teilweise noch hinter den Variablen in den Strukturen. Etwas seltsam, aber nur so ging es.
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.