Forum: Compiler & IDEs vier bytes aus char array -> integer


von Nik Bamert (Gast)


Lesenswert?

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

von Werner B. (Gast)


Lesenswert?

1. vier bytes ergeben auf einem AVR ein unsigned long.
2. root_dir_first_cluster = *((unsigned long)&buffer[BPB_RootClus]);

;)

von Werner B. (Gast)


Lesenswert?

Sorry...

2. root_dir_first_cluster = *((unsigned long *)&buffer[BPB_RootClus]);

von Werner B. (Gast)


Lesenswert?

...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

von Nik Bamert (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

> 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.

von Norman M. (norman)


Lesenswert?

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

von Norgan (Gast)


Lesenswert?

Kein struct, eine union wäre das erste Mittel der Wahl.

von Norman M. (norman)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Norgan (Gast)


Lesenswert?

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
}

von Norman M. (norman)


Lesenswert?

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

von krase (Gast)


Lesenswert?

> Jetzt muss ich das Padding nur  noch wegbekommen.

Das sollte eigentlich mit
1
__attribute__ ((packed))
 funktionieren.

von Norman M. (norman)


Lesenswert?

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
Noch kein Account? Hier anmelden.