Hallo,
ich suche derzeit eine eindeutige Antwort/Quelle auf folgende Frage.
Wird der Aufbau von Strukturen in C 1:1 im Speicher übernommen - heist
werden die einzelnen Elemente einer Struktur in der gleichen Reihenfolge
im Speicher abgelegt, wie sie in der Struktur definiert wurden.
Beispiel:
1
structadam{
2
charc_var;
3
charc_var_2;
4
charc_var_3;
5
...};
wird das dann auch im Speicher so abgelegt?
Anahme: Ram mit Ausrichtung Byte
RAM: Byteaddresse 1: c_var
+1Byte c_var_2
+2Byte c_var_3
Grund für meine Frage ist ein Programmbeispiel welches über Pointer auf
die Elemente einer Struktur zugegriffen hat. Bisher hielt ich das für
heikel... aber anscheinend gehts ... Zufall?
mfg
Gary
wenn du es so wie im beispiel hinschreibst dann ist es nicht festgelegt.
Der Compiler kann es machen wie er will.
Wenn man das Schlüsselwort packet verwendet, dann ordnet er es so wie du
willst - kann aber zu einer schlechten Performance kommen.
Die Reihenfolge bleibt bestehen aber der compiler wird die einzelnen
variablen an speichergrenzen ausrichten (alignment). Bei 32bit
prozessoren beispielsweise 4B.
Deine 3 chars werden schon hintereinander liegen aber folgende
konstellation nicht mehr:
1
struct{
2
chara;
3
longb;
4
}
Hier wird hinter dem char 3B freigelassen (padding) damit der 4-byte
long auch an einer 4-byte grenze ausgerichtet wird. Insgesamt nimmt das
struct also 8B in Anspruch.
Du kannst aber _attribute_ ((packed)) nutzen (siehe "using GCC") um
den compiler zu zwingen, die variablen ohne padding anzuordnen. wenn
dann allerdings ein long unaligned im speicher liegt, wird der zugriff
darauf vermutlich mehr Zeit in anspruch nehmen, weil der prozessor nur
auf an 4B Grenzen ausgerichtete 4B integer zugreifen kann.
Das zugreifen mit pointern auf struct-member ist problematisch, wenn es
ein pointer typ ungleich des struct pointers ist, also z.B. char*. Bei
Optimierung höher O1 wird gcc keinen funktionierenden code mehr
produzieren (Stichworte: pointer aliasing, strict aliasing rules).
nötig ist das aber manchmal, beispielsweise um netzwerk-packete oder
genauer dessen header-felder, die zusammenhängend im speicher liegen zu
lesen oder zu beschreiben. die protokoll header sind aber zum glück so
aufgebaut, dass der zugriff immer aligned ist. zumindest bei wenigen mir
bekannten protokollen wie UDP, IP, ethernet II.
hier was zum thema aliasing:
http://mail-index.netbsd.org/tech-kern/2003/08/11/0001.html
und compiler spezifisches hier:
http://gcc.gnu.org/onlinedocs/gcc-4.0.2/gcc.pdf
Danke Peter, Danke Daniel für die schnelle Antwort ...
Daniel G. schrieb:
> Die Reihenfolge bleibt bestehen aber der compiler wird die einzelnen> variablen an speichergrenzen ausrichten (alignment). Bei 32bit> prozessoren beispielsweise 4B.>> Deine 3 chars werden schon hintereinander liegen aber folgende> konstellation nicht mehr:>>
1
struct{
2
>chara;
3
>longb;
4
>}
>> Hier wird hinter dem char 3B freigelassen (padding) damit der 4-byte> long auch an einer 4-byte grenze ausgerichtet wird. Insgesamt nimmt das> struct also 8B in Anspruch.
Das hatte ich auch so verstanden - deswegen fügte ich den Hinweis
Ausrichtung Byte ein.
> Du kannst aber _attribute_ ((packed)) nutzen (siehe "using GCC") um> den compiler zu zwingen, die variablen ohne padding anzuordnen. wenn> dann allerdings ein long unaligned im speicher liegt, wird der zugriff> darauf vermutlich mehr Zeit in anspruch nehmen, weil der prozessor nur> auf an 4B Grenzen ausgerichtete 4B integer zugreifen kann.
Genau und damit würde ich beim Zugriff über Pointer ohne (packed) immer
wieder ins Leere greifen - sollte der Pointer (vom Typ char) einfach nur
inkrementiert werden.
Aber mal angenommen es ist dann nur ein Datentyp verwendet ... könnte
das mit dem (packed) ja funktionieren. Das ist dann aber GCC spezifisch
... haben andere Compiler ähnliche "Anweisungen"?
> hier was zum thema aliasing:> http://mail-index.netbsd.org/tech-kern/2003/08/11/0001.html
Beim schnellen Überfliegen, wird hier über den Zugriff auf
unterschiedliche Datentypen durch einen Pointer (eines bestimmten
Datentyps) gesprochen... aber ich verste das erste Beispiel schon nicht
>> so a write through a pointer may change any variable in a program:>>>> int i = 23;>> *f = 5;>> /* We don't know what value i has at this point. */>>>> We cannot know what value i has, since the pointers &i and f may point>> at the same address (that is what ISO C means when it say that &i and f>> may alias).
das Beispiel ist mir zu knapp - um es zu verstehen, weil ich nichts von
f weiss ... wieso sollte er i beeinflussen?
Zusammenfassung wäre für mich ...
Zugriff (nicht gecastet) auf Inhalte unterschiedlicher Datentypen über
einen Pointer können schief gehen, da der Compiler/Linker, die Addressen
je nach Datentyp (Länge) anders ausrichten kann -> siehe (packed).
>> und compiler spezifisches hier:> http://gcc.gnu.org/onlinedocs/gcc-4.0.2/gcc.pdf
danke ;O) .... lies sich nicht so schnell lesen ;O)
Wäre das nicht ein paar Zeilen im GCC-Tutorial wert?
Dort werden Zeiger eh nur kurz gestreift.
Vermutlich bekomme ich gleich nen Kommentar, dass dies definitiv kein
"Einsteiger" interessieren würde ;)
Gruss,
Gary
>Zusammenfassung wäre für mich ...>Zugriff (nicht gecastet) auf Inhalte unterschiedlicher Datentypen über>einen Pointer können schief gehen, da der Compiler/Linker, die Addressen>je nach Datentyp (Länge) anders ausrichten kann -> siehe (packed).
Wobei ein Zugriff über Pointer auf EINEN Member eines structs
grundsätzlich problemlos ist. Problematisch ist nur der Zugriff auf
andere Member über diesen einen Pointer mittels Pointerarithmetik. Und
da stellt sich dann schon die Frage, ob das dann noch sauberer
Programmierstil ist, und in ein Tutorial gehört.
Oliver
G. B. schrieb:
> Vermutlich bekomme ich gleich nen Kommentar, dass dies definitiv kein> "Einsteiger" interessieren würde ;
Im Gegenteil. Der belesene Einsteiger (Kernighan & Ritchie) kommt aus so
eine Idee garnicht:
> Zugriff (nicht gecastet) auf Inhalte unterschiedlicher Datentypen über> einen Pointer
Deine "Erwartungshaltung" ist hier unangebracht.
Nur weil Du denkst etwas müsse so und so sein, heisst das noch nicht
das es so ist.
Oliver schrieb:
> Wobei ein Zugriff über Pointer auf EINEN Member eines structs> grundsätzlich problemlos ist. Problematisch ist nur der Zugriff auf> andere Member über diesen einen Pointer mittels Pointerarithmetik. Und> da stellt sich dann schon die Frage, ob das dann noch sauberer> Programmierstil ist, und in ein Tutorial gehört.
Wie schon beschrieben habe ich bei eingehenden Paketen, die in einem
char-array landen (RX-buffer), einen struct-pointer auf jeden der Header
gesetzt. Die (packed) structs entsprechen den headern, so dass ich
direkt auf die felder zugreifen kann. das ist sehr übersichtlich und
effizient.
Wie sieht denn so etwas in "sauberem" programmierstil aus?
Deine Frage:
>>> int i = 23;>>> *f = 5;>>> /* We don't know what value i has at this point. */>>>>>> We cannot know what value i has, since the pointers &i and f may point>>> at the same address (that is what ISO C means when it say that &i and f>>> may alias).> das Beispiel ist mir zu knapp - um es zu verstehen, weil ich nichts von> f weiss ... wieso sollte er i beeinflussen?
betrifft eine ganz andere Baustelle. Eben weil nichts über f bekannt
ist, kann der Compiler nach *f = 5 nichts mehr über den Inahlt von i
wissen[1]. Er kann also ein nachfolgendes
1
intj=10*i;
nicht mehr einfach durch
1
intj=230;
ersetzen, da i durch das Schreiben nach *f verändert worden sein kann.
Ohne das *f dürfte der Compiler das.
__
[1] Um genau zu sein: Er kann wissen, dass i entweder 5 oder 23 ist.
Das nützt für Optimierungen aber nichts.
Daniel G. schrieb:
> Die (packed) structs entsprechen den headern, so dass ich> direkt auf die felder zugreifen kann. das ist sehr übersichtlich und> effizient.
Es gibt Architekturen, bei denen du sowas einfach nicht mehr
machen kannst, weil du mit einem unaligned trap rausfliegst (statt
nur ineffektiv zu werden wie auf einem IA32 oder IA64). Dafür
genügt schon eine Portierung auf einen ARM. Ganz finster wird's
dann, wenn du auch noch byte-order-Probleme bei einer Portierung
bekommen kannst, beispielsweise bei einer Portierung auf UltraSPARC
oder sowas.
> Wie sieht denn so etwas in "sauberem" programmierstil aus?
Einzeln zusammenbauen, auch wenn's drei CPU-Takte mehr kostet.
Daniel G. schrieb:
> Oliver schrieb:>> Wobei ein Zugriff über Pointer auf EINEN Member eines structs>> grundsätzlich problemlos ist. Problematisch ist nur der Zugriff auf>> andere Member über diesen einen Pointer mittels Pointerarithmetik. Und>> da stellt sich dann schon die Frage, ob das dann noch sauberer>> Programmierstil ist, und in ein Tutorial gehört.>> Wie schon beschrieben habe ich bei eingehenden Paketen, die in einem> char-array landen (RX-buffer), einen struct-pointer auf jeden der Header> gesetzt. Die (packed) structs entsprechen den headern, so dass ich> direkt auf die felder zugreifen kann. das ist sehr übersichtlich und> effizient.>> Wie sieht denn so etwas in "sauberem" programmierstil aus?
Bei dir ist das schon ok so.
Oliver spricht von ganz anderen, völlig unsauberen Dingen. Das Problem:
Mit einem Cast (um den du hier im Grunde nicht rumkommst) kannst du
einen Compiler zu allem zwingen. Noch problematischer wird die
Situation, wenn man den Cast an die falsche Stelle setzt und sich zuerst
den Struct-Member mittels Pointer-Arithmetik bestimmt und dann erst von
dort wegcastet. Dein Fall sieht aber anders aus. Du hast einen unsigned
char Buffer und castest dir eine Startadresse in diesem Buffer auf einen
'Pointer zu Header' um und greifst dann ganz normal auf den Header zu.
unsigned char Buffer[...];
struct Header* pPtr = (struct Header* )Buffer[x];
Length = pPtr->Length; // wenn zb ein Length Feld im Header
existiert
ausser auf das Padding(und ev. die Byte Order) musst du dabei eigentlich
auf nicht viel aufpassen. Allerdings ist Padding immer
Compilerspezifisch. Von daher kann man hier keine allgemeinen Regeln
angeben ausser: Sieh im Compilermanual unter Padding nach und wie man es
auf einen bestimmten Wert zwingt bzw. abschaltet. Dazu kommt natürlich
noch, dass man sich hier eigentlich um das Padding auf 2 Seiten kümmern
muss. Auf der einen Seite könnte der Sender bereits ein Padding in den
gesendeten Daten haben; auf der anderen Seite könnte der Compiler auf
der Empfangsseite in die struct Header ein Padding eingearbeitet haben.
(Mir ist auch nicht klar, warum hier das Thema 'Aliasing' aufgebracht
wurde. IMHO hat das mit der eigentlichen Fragestellung nichts zu tun.
Bei Aliasing geht es darum, was der Compiler annehmen darf und was er
nicht annehmen darf, wenn über einen Pointer zugegriffen wird)
Daniel G. schrieb:
> Wie schon beschrieben habe ich bei eingehenden Paketen, die in einem> char-array landen (RX-buffer), einen struct-pointer auf jeden der Header> gesetzt. Die (packed) structs entsprechen den headern, so dass ich> direkt auf die felder zugreifen kann. das ist sehr übersichtlich und> effizient.>> Wie sieht denn so etwas in "sauberem" programmierstil aus?
Es wäre besser wenn Du Code zeigst. Im Prinzip habe ich das auch schon
so wie Du gemacht. Aber die Frage ist wie Du den Zeiger auf die Elemente
bildest.
Mmmh schrieb:
> G. B. schrieb:>> Vermutlich bekomme ich gleich nen Kommentar, dass dies definitiv kein>> "Einsteiger" interessieren würde ;>> Im Gegenteil. Der belesene Einsteiger (Kernighan & Ritchie) kommt aus so> eine Idee garnicht:>>> Zugriff (nicht gecastet) auf Inhalte unterschiedlicher Datentypen über>> einen Pointer>> Deine "Erwartungshaltung" ist hier unangebracht.> Nur weil Du denkst etwas müsse so und so sein, heisst das noch nicht> das es so ist.
Sorry - wie du in meinem Beitrag oben lesen kannst... ist das nicht
meine Erwartungshaltung... drauf gekommen bin ich über ein Beispiel
darauf gekommen.
nämlich das Beispiel zum DCF77 von Peter Dannegger (erstes Posting)
Beitrag "DCF77 Uhr in C mit ATtiny26"
Auserdem ging es mir dabei nicht um die structs sondern um das Thema
Allingment... sorry da war ich nicht präzise.
Jörg Wunsch schrieb:
> Es gibt Architekturen, bei denen du sowas einfach nicht mehr> machen kannst, weil du mit einem unaligned trap rausfliegst (statt> nur ineffektiv zu werden wie auf einem IA32 oder IA64). Dafür> genügt schon eine Portierung auf einen ARM. Ganz finster wird's> dann, wenn du auch noch byte-order-Probleme bei einer Portierung> bekommen kannst, beispielsweise bei einer Portierung auf UltraSPARC> oder sowas.
Hier zitiere ich mich selbst:
Daniel G. schrieb:
> die protokoll header sind aber zum glück so> aufgebaut, dass der zugriff immer aligned ist. zumindest bei wenigen mir> bekannten protokollen wie UDP, IP, ethernet II.
Es ist Software für einen ARM9.
Hier das Struct für den IP header:
1
/* IP header */
2
structip_typ{
3
unsignedcharversion_header;
4
unsignedcharTOS;
5
unsignedshortlength;
6
unsignedshortid;
7
unsignedshortflags_offset;
8
unsignedcharTTL;
9
unsignedcharprot;
10
unsignedshortchksum;
11
unsignedintsrcIP;
12
unsignedintdestIP;
13
}__attribute__((packed));
Es gibt einen einheitlichen Packet descriptor für RX und TX:
1
structPD_typ{
2
3
/* buffer location */
4
unsignedintStartOfFrame;
5
unsignedintEndOfFrame;
6
7
/* header pointer */
8
structeth_typ*eth_header;
9
structip_typ*ip_header;
10
structudp_typ*udp_header;
11
12
/* PMI communication protocol */
13
structPMI_prot_typ*PMI_prot;
14
15
/* PMI data length */
16
unsignedintdata_length;
17
18
};
Wenn ein Paket empfangen wurde, werden hier die pointer gesetzt:
G. B. schrieb:
> Sorry - wie du in meinem Beitrag oben lesen kannst... ist das nicht> meine Erwartungshaltung... drauf gekommen bin ich über ein Beispiel> darauf gekommen.
Es ist doch für eine Erwartungshaltung völlig irrelevant ob Du sie
selbst entwickelt hast oder durch einen Anderen darauf gebracht wurdest,
Meister.
Postest Du bitte Deinen Code?
Der Vollständigkeit halber, selbst wenn es nicht zur Frage gehört, hier
noch ein Link in dem es auch um Aliasing issues geht (unter "non-bugs"
und dann unter "C"):
http://gcc.gnu.org/bugs/
Überhaupt eine gute Seite, auch die anderen vermeintlichen compiler bugs
sollte man kennen :-)
Leider ist das Thema nun ein bischen ausgeufert...
DANKE für die vielen Antworten... ich hoffe nun aber die Antwort auf
meine Frage korrekt zu formulieren....
Beim Anlegen von structs im Speicher durch den Compiler/Linker kann
nicht von einer Anordnung der Struct-Elemente analog zur Deklaration
ausgegangen werden. Durch Optimierungen, wie z.B. Allignment, können die
Variablen an nicht aufeinanderfolgenden Adressen liegen. Das heist bei
einem Pointer-Zugriff über Offset (wie im Beispiel der DCF77-Uhr) können
fehlerhafte Zugriffsaddressen erzeugt werden.
Kann man das so zusammen fassen?
Gruss,
Gary
PS: an Mmmh (Gast)
Bevor du hier jemanden abfällig mit "Meister" betitulierst würde ich
vorschlagen das du dich hier im Forum anmeldest und vor allem das du die
Postings liest, denn dann wüsstest du das es hier um eine grundsätzliche
Frage geht und nicht um einen Code den ich geschrieben habe.
G. B. schrieb:
> Kann man das so zusammen fassen?
So würde ich es formulieren:
Reihenfolge bleibt, aber evtl. werden durch den compiler Leerräume
eingefügt "padding" um durch korrektes alignment einen schnellen zugriff
zu gewährleisten. Das padding kann durch __attribute__((packed))
aufgehoben werden.
Eine andere Möglichkeit ohne Castings auf gleiche Speicherbereiche mit
unterschiedlichen Datentypen zuzugreifen ist übrigens ein Union zu
nutzen:
G. B. schrieb:
> würde ich> vorschlagen das du dich hier im Forum anmeldest
Das ist garnicht nötig. Ich kann mich auch ohne Anmeldung abfällig
äussern.
Daniel G. schrieb:
> Und das ist ISO-C konform.
Nicht wirklich :-)
Das zeigt, bei der angestrebten Verwendungsform, genauso undefiniertes
Verhalten, wie das Umcasten eines Pointers.
Eine union hat nur dann definiertes Verhalten, wenn man über denselben
Member die Daten wieder herausliest, über den sie auch hineingeschrieben
wurden. Über access_bytes schreiben und über access_words lesen verletzt
genau dieses Prinzip und man landet damit automatisch bei undefiniertem
Verhalten.
G. B. schrieb:
> Beim Anlegen von structs im Speicher durch den Compiler/Linker kann> nicht von einer Anordnung der Struct-Elemente analog zur Deklaration> ausgegangen werden. Durch Optimierungen, wie z.B. Allignment, können die> Variablen an nicht aufeinanderfolgenden Adressen liegen. Das heist bei> einem Pointer-Zugriff über Offset (wie im Beispiel der DCF77-Uhr) können> fehlerhafte Zugriffsaddressen erzeugt werden.
Ja. Der C Standard lässt einige Details (bewusst) offen, die aber
damit nicht zwangsläufig vom Compiler abhängig sind (gibt's auch),
sondern von der Zielarchitektur.
Setzt man sich mit dem ABI der Zielarchitektur auseinander, kann man
dieses Verfahren (ptr+offset) durchaus sinnvoll einsetzen.
Kurz: Wisse was Du tust.
Gruß
Marcus
@ G. B.
Das hast Du wirklich in den falschen Hals bekommen. Weder meine
Bemerkung zu Deiner Erwartungshaltung noch die Anrede "Meister" war
abfällig gemeint, wenn auch letzteres natürlich nicht ernst gemeint war.
Um ein wenig meinen guten Willen zu zeigen:
> Beim Anlegen von structs im Speicher durch den Compiler/Linker kann> nicht von einer Anordnung der Struct-Elemente analog zur Deklaration> ausgegangen werden.
Nein. Man kann davon ausgehen das die Adressen der Elemente in der
Reihenfolge aufsteigen, wie sie in der Deklaration angegeben sind.
Darüber hinaus ist der Zeiger auf die Struktur identisch mit dem Zeiger
auf das erste Element. Siehe K&R, 2. Auflage, S. 209
> Durch Optimierungen, wie z.B. Allignment, können die> Variablen an nicht aufeinanderfolgenden Adressen liegen.
"Alignment" ist eine Eigenschaft, kein Vorgang. Der Vorgang heisst
"Padding" und kann durch das pragma "packed" oder andere Optionen
verhindert werden.
> Das heist bei> einem Pointer-Zugriff über Offset (wie im Beispiel der DCF77-Uhr) können> fehlerhafte Zugriffsaddressen erzeugt werden.
Nicht grundsätzlich. Aber dazu müsste man (verd... nochmal) den Code
sehen, auf den Du Dich beziehst.
Mit gutem Stil ist hier gemeint, sich in der Programmformulierung
nicht auf eine bestimmte Anordnung zu verlassen soweit sie nicht
definiert ist.
D.h in dem konkreten Fall, das Du den Zeiger von einem Strukturelement
nicht als Ausgangspunkt für die Berechnung des Zeigers auf das nächste
Element nimmst, sondern wieder auf den ursprünglichen Zeiger auf die
Struktur zurückgreifst.
Karl heinz Buchegger schrieb:
> Nicht wirklich :-)> Das zeigt, bei der angestrebten Verwendungsform, genauso undefiniertes> Verhalten, wie das Umcasten eines Pointers.>> Eine union hat nur dann definiertes Verhalten, wenn man über denselben> Member die Daten wieder herausliest, über den sie auch hineingeschrieben> wurden. Über access_bytes schreiben und über access_words lesen verletzt> genau dieses Prinzip und man landet damit automatisch bei undefiniertem> Verhalten.
Mist!
Danke für die Verbesserung!
Aber immerhin läuft diese Methode mit Optimierung >O1, also mit
-fstrict-aliasing:
Aus "using gcc":
1
The practice of reading from a different union member than the one
2
most recently written to (called “type-punning”) is common. Even with
3
‘-fstrict-aliasing’, type-punning is allowed, provided the memory is
4
accessed through the union type. So, the code above will work as expected.
@Mmmh ... geht also doch auch normal ;)
um es konkret zu machen hatte ich den Link angehängt....
Wobei ich jetzt aber das Thema auf die Speicherablage verdichtet hatte.
Aber weil ich deinen guten Willen würdige
- das klingt vielleicht ;O) -
hier den kopierte Code.
Zusammenfassung aus dem Beispiel
Deklaration in clock.h
1
structtime{
2
u8second;
3
u8minute;
4
u8hour;
5
u8day;
6
u8wday;
7
u8month;
8
u8year;
9
};
Verwendung und Zugriff in dcf77.c
1
structtimenewtime;
2
...
3
voiddecode_dcf77(u8pulse)
4
{
5
u8*d;
6
....
7
d=(u8*)&newtime.minute+(i>>4);// byte address
8
i&=0x0F;// bit number
9
if(i==0)
10
*d=0;// clear all, if lsb
11
if(pulse)
12
*d+=LPM(&BMASK[i]);// set bit
13
....
Und d = (u8 *)&newtime.minute + (i >> 4);
kann hat mich eben stutzig gemacht, bzw. kann auch daneben gehen.
G. B. schrieb:
> @Mmmh ... geht also doch auch normal ;)> Aber weil ich deinen guten Willen würdige
Seufz. Kaum gibt man den kleinen Finger...
Dann sieh mal selbst zu wenn Du meinst Dir diesen Ton erlauben zu
können.
G. B. schrieb:
>> Und d = (u8 *)&newtime.minute + (i >> 4);> kann hat mich eben stutzig gemacht, bzw. kann auch daneben gehen.
Im Prinzip schon.
Allerdings wissen wir, dass es auf dem AVR kein Padding gibt.
Aber im Grunde hast du recht. Die (softwaretechnisch etwas bessere)
Alternative ist allerdings gleich um ein gutes Stück aufwändiger, so
dass man mit der Einschränkung 'ist auf einem AVR mit avr-gcc ok' leben
kann.
@Karl-Heinz:
Danke - stimmt - das hab ich auch so verstanden.
@Mmmh:
Irgendwie scheine wir grundsätzlich andere Wahrnehmungen zu haben.
Ton kam von dir. Meine Antwort war aber nicht "böse" gemeint, schon gar
nicht wollte ich die angebotene Hand ausschlagen
Meine Antwort war - zugegeben - etwas sarkastisch (siehe smilys), was
jemand der selber holzt aber verstehen sollte.
Egal - Gott sei Dank - gibt es Leute die sich im Forum ANMELDEN und
Beiträge schreiben die fair und sachlich sind.
Daniel G. schrieb:
> die protokoll header sind aber zum glück so> aufgebaut, dass der zugriff immer aligned ist. zumindest bei wenigen mir> bekannten protokollen wie UDP, IP, ethernet II.
Von wegen! Da will ich mich mal eben korrigieren, nicht dass da einer
stolpert:
Der Ethernet II header besteht aus 14B und damit ist alles was danach
kommt (IP, UDP...) für 4B nicht mehr aligned. :-(
sorry!