Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

alignment mit gcc

9 views
Skip to first unread message

Steffen

unread,
Apr 15, 2002, 4:06:20 PM4/15/02
to
Hallo zusammen,

für den Datenaustausch eines Programmes über TCP / IP Sockets wird
eine Struktur benutzt.
Nun soll ich für das Programm einen Linux Client schreiben.

Für diese Struktur wurde unter dem Windows Compiler immer #pragma pack
(push,2) verwendet, was ja meines wissens die Struktur mit dem
alignment 2 im Speicher ablegt.

Die Struktur hat wenn ich

test int;
int = sizeof(structur)

684 Bytes unter Windows.

Mache ich dasselbe unter Linux hat die Struktur nur eine Größe von 673
Bytes.
Für den Datenaustausch sollten die Strukturen ja aber gleich groß
sein.

Wie schaffe ich das? Wie veränder ich das alignment einer Struktur
wenn ich den gcc verwende. #pragma pack (2) compiliert er zwar, aber
auswirkungen zeigen sich keine. Meine Struktur bleibt unter Linux 273
Bytes groß.
Was tun?

Auch folgednes hat keine Auswirkungen:

struct beispiel
{
char a[20];
char b[2];

}__attribute__((aligned(2)));

Felix von Leitner

unread,
Apr 15, 2002, 3:12:18 PM4/15/02
to
Thus spake Steffen (Steffe...@t-online.de):

> für den Datenaustausch eines Programmes über TCP / IP Sockets wird
> eine Struktur benutzt.
> Nun soll ich für das Programm einen Linux Client schreiben.

Binär? Da war offensichtlich ein echter Experte am Werk. Das wird
wahrscheinlich nicht mal mit der nächsten 64-bit Windows-Version noch
funktionieren. Ganz großartig, feuere den Vollidioten, der das gemacht
hat, und heuert jemanden an, der sich mit Protokolldesign auskennt.

Ach ja, das Lesen der C FAQ hat auch noch keinem geschadet.

Peter Simons

unread,
Apr 15, 2002, 4:57:25 PM4/15/02
to
> int = sizeof(structur)

Alignment bezieht sich nicht auf die Größe der Struktur sondern
darauf, daß sie auf eine Adresse gelegt werden soll, für die

Adresse modulo Alignment

gleich Null ist.

Du suchst -- fürchte ich -- an der völlig falschen Stelle. Wenn Du
sicherstellen willst, daß beide Strukturen gleich groß sind (wobei Du
eigentlich meinst, daß alle _Elemente_ der Struktur jeweils gleich
groß sind) ... Vergiß es. Nichts garantiert Dir, daß zwei "int"s auch
nur dann gleich groß sind, wenn Du das Programm auf demselben Rechner
mit verschiedenen Compilern übersetzt.

Datenstrukturen zwischen Rechnern zu übertragen ist keine ganz
einfache Aufgabe. Eine Bibliothek, die das für Dich lösen kann, ist
beispielsweise unter

http://www.ossp.org/pkg/lib/xds/

zu finden. Allerdings mußt Du diese oder eine ähnliche Funktionalität
natürlich auch in die Windows-Version einbauen. Nicht, damit diese mit
der Linux-Version zuverlässig reden kann, sondern schon damit die
beiden Windows-Versionen _zuverlässig_ miteinander reden können.

Es kann nicht schaden, wenn Du in einem C-Buch Deines Vertrauens
nochmal über das Thema "Datentypen" insbesondere mit Hinblick auf
"Portabilität" nachliest. Das _kann_ alles ganz leicht sein, aber man
muß genau wissen, was man tut.

jsaul

unread,
Apr 15, 2002, 5:18:50 PM4/15/02
to
Steffen <Steffe...@t-online.de> wrote:

> für den Datenaustausch eines Programmes über TCP / IP Sockets wird
> eine Struktur benutzt.
> Nun soll ich für das Programm einen Linux Client schreiben.

man xdr

Sollte heutzutage auf allen Unix-Systemen verfügbar sein.

Wenn's auf Performance nicht ankommt, und insbesondere auch bei kleinen zu
übertragendem Datenvolumen, kannst du selbstverständlich auch ASCII nehmen.
Beide Lösungen setzen jedoch voraus, dass auch die "Gegenseite"
entsprechend angepasst wird.

Gruß, jsaul

Patrick Schaaf

unread,
Apr 16, 2002, 2:14:44 AM4/16/02
to
Steffe...@t-online.de (Steffen) writes:

>für den Datenaustausch eines Programmes über TCP / IP Sockets wird
>eine Struktur benutzt.

Das ist ein Fehler.

Da Du die Gegenseite wohl nicht aendern kannst, verstehe, wie die
Daten "Byte fuer Byte" ankommen, und greife auf sie in Form eines
char-Arrays zu. Musst Du etwas senden, tust Du das Gleiche. So wird
Dein Code von Anfang an portabel auf andere Platform/Compiler-
Kombinationen - und Fragen zu compilerspezifischen Packungspragmas
kannst Du Dir voellig sparen.

Gruss
Patrick

Steffen

unread,
Apr 16, 2002, 2:41:51 AM4/16/02
to
> Binär? Da war offensichtlich ein echter Experte am Werk. Das wird
> wahrscheinlich nicht mal mit der nächsten 64-bit Windows-Version noch
> funktionieren. Ganz großartig, feuere den Vollidioten, der das gemacht
> hat, und heuert jemanden an, der sich mit Protokolldesign auskennt.


Hm, als Diplomant kann ich den schlecht feuern *g*


Aber wenn ich mir das alles so durchlese habe ich das Gefühl ich
bekomme ein Problem. Auf der Windows Seite darf ich leider nichts
verändern.

Danke für die Hilfe.

Heinrich Schramm

unread,
Apr 16, 2002, 2:58:35 AM4/16/02
to
Peter Simons <sim...@cryp.to> wrote:

>Alignment bezieht sich nicht auf die Größe der Struktur sondern
>darauf, daß sie auf eine Adresse gelegt werden soll, für die
>
> Adresse modulo Alignment
>
>gleich Null ist.

Ich nehme an, Steffen bezieht sich auf das Alignment innerhalb der
Struktur. Wenn man unterschiedlich grosse Datentypen (8-, 16-,
32-Bit-Werte) in der Struktur verwendet, werden je nach Alignment auf
verschiedenen Rechnern mehr oder weniger Dummy-Bytes eingefuegt.

>Du suchst -- fürchte ich -- an der völlig falschen Stelle.

Ja. Selbst wenn er das Alignment (durch unschoene Tricks) in den Griff
bekommt, bleibt das Problem mit Little und Big Endian. Bei irgendeinem
neuen Rechner wird er damit garantiert einmal auf die Nase fallen. Die
saubere Methode ist, die Daten so zu beschreiben, wie sie byteweise
ueber die Leitung gehen, und sie dann an jedem Uebertragungsendpunkt
wieder in die lokale interne Darstellung umzusetzen.

Gruss Heiner

Bernhard Trummer

unread,
Apr 16, 2002, 4:36:21 AM4/16/02
to
Felix von Leitner <usenet-...@fefe.de> wrote:
> Das wird wahrscheinlich nicht mal mit der nächsten 64-bit
> Windows-Version noch funktionieren.

Oder mit einem Client, dessen Prozessor eine Big-Endian Byteorder
statt Little-Endian hat...

--
No sig @ work.

Stefan Nobis

unread,
Apr 16, 2002, 5:21:56 AM4/16/02
to
Peter Simons <sim...@cryp.to> writes:

> Datenstrukturen zwischen Rechnern zu übertragen ist keine ganz
> einfache Aufgabe. Eine Bibliothek, die das für Dich lösen kann, ist
> beispielsweise unter
>
> http://www.ossp.org/pkg/lib/xds/

Oder (neben der Möglichkeit strings zu verwenden) man xdr.

--
Stefan.

Markus Lausser

unread,
Apr 16, 2002, 10:47:15 AM4/16/02
to
On 15 Apr 2002 13:06:20 -0700, Steffen wrote:
>
> [binaerer daten Austausch ueber TCP]

zu OP: wenn dein Protocol nicht festlegt, in welchem
Format die Daten gesendet werden, dann hast Du ein Problem.
Du koenntest hoechstens raten, wie dein Win Rechner die daten
sendet. Ich sehe die einzige Moeglich darain, entweder Daten
in nem festen Format zu senden, oder mitzusenden, in welchem
Format die daten gesendet wird. 2ters will ich machen:

Ich habe exact das gleiche Problem, nur dass ich das Protocol
selbst entwerfen darf. Clients sind untereinander verbunden,
lassen sich von externen Modulen Daten generieren und schicken
diese Daten dann an nen anderen Client. Der client hat mittels
einer Metabeschreibungssparche ahnung darueber, welche Daten
er zu senden hat (zB. RECORD { int char }) oder empfangen wird.

Da das ganze nur auf Linux/Unix laufen soll und der Datenaustausch,
moeglichst effizient sein soll, habe ich mich
entschlossen, die Daten, so wie sie von einem Modul generiert
werden, samt Speicherlayoutinfo zu senden. Der empfangende
Client muss diese dann in das Speicherlayout seines eigenen
Rechners konvertieren, und dann werden sie dem eingenen
Modul als Input uebergeben (der dann nur noch seine
struct/wasauchimmer darauf verweisen laesst.

Tests haben gezeigt, dass der einzige unterschied zwischen
meinen testrechnern (linux/pc und Solaris/sparc) die byte
order ist. windows/mac/etc clients soll es nie geben, ich will
diese aber grundsaetzlich beruecksichtigen, d.h. es sollte
moeglich sein, auch nen win client zu implementieren.

Nun stellt sich fuer mich die Frage:
* welche Unterschiede kann es zwischen verschiedenen
rechner ueberhaupt geben, d.h. was brauche ich als
speicherlayout info, damit ich das Datenformat vollstaendig
beschrieben habe? (ich will aber keine hoechst seltenen
Rechnerarchitektueren wie Cray oder sowas berucksichtigen,
sondern nur "standard machines".
Mir faellen hier nur 2 Dinge ein:
- byte order
- alignment
Eigentlich stellt sich die Frage, welche Unterschiede es
bei array, struct, union, enum geben kann.
* Wo wem haengen diese Unterschiede ab? Ist das ausschliesslich
rechnerabhaengig, oder beispielsweise auch compilerabhaengig?


Markus.

Klaus von der Heyde

unread,
Apr 16, 2002, 11:05:44 AM4/16/02
to
Markus Lausser <lau...@sauron.forwiss.uni-passau.de> wrote:
>
> Tests haben gezeigt, dass der einzige unterschied zwischen
> meinen testrechnern (linux/pc und Solaris/sparc) die byte
> order ist.

Dafuer gibt es ja entsprechende funktionen. ntohl usw. Damit kannst
du sogar auf beiden systemen den exakt gleichen quellcode verwenden.
Ach ja: das geht nur bei integer-zahlen, nicht bei floats.

Interessant wird es, wenn architekturen mit verschiedener wortbreite
zusammen arbeiten muessen. Wie lang ist ein "int"?
Mindestens solltest du in den datenstrukturen die groesse der zahlen
explizit angeben.

Beispiel: die IP, UDP und TPC header sind auch binaer codiert, und
jeder rechner muss damit umgehen koennen.

> windows/mac/etc clients soll es nie geben,

Sag niemals nie.

Klaus

--
Klaus von der Heyde -- he...@informatik.uni-bonn.de

Christian Weisgerber

unread,
Apr 16, 2002, 2:40:35 PM4/16/02
to
Markus Lausser <sg...@users.sourceforge.net> wrote:

> * welche Unterschiede kann es zwischen verschiedenen
> rechner ueberhaupt geben, d.h. was brauche ich als
> speicherlayout info, damit ich das Datenformat vollstaendig
> beschrieben habe?

> Mir faellen hier nur 2 Dinge ein:


> - byte order
> - alignment

- Typgröße. sizeof(long) = ?

- Padding, also die Auspolsterung von structs auf Alignment-Grenzen.

Falls du mit "Alignment" in Wirklichkeit Padding gemeint hast,
dann musst du noch Alignment berücksichtigen, also die Ausrichtung
von Datentypen, die mehrere Bytes groß sind, an Adressen, die ein
ganzzahliges Vielfaches dieser Größe sind, bei allen _Zugriffen_.

Falsche Ausrichtung wird je nach Architektur und Systemkonfiguration
bestraft mit:
* Langsamer Zugriff, um ein paar Taktzyklen (z.B. i386).
* Sehr langsamer Zugriff, ein paar Tausend Taktzyklen (z.B. Alpha
mit Fixup).
* SIGBUS (z.B. Alpha ohne Fixup, Sparc).

> (ich will aber keine hoechst seltenen Rechnerarchitektueren wie
> Cray oder sowas berucksichtigen, sondern nur "standard machines".

Je nachdem, ob du VAX als "höchst selten" betrachtest:

- Gleitkommaformat.

--
Christian "naddy" Weisgerber na...@mips.inka.de

Rudolf Polzer

unread,
Apr 16, 2002, 3:58:11 PM4/16/02
to
Christian Weisgerber <na...@mips.inka.de> wrote:
> Markus Lausser <sg...@users.sourceforge.net> wrote:
> > * welche Unterschiede kann es zwischen verschiedenen
> > rechner ueberhaupt geben, d.h. was brauche ich als
> > speicherlayout info, damit ich das Datenformat vollstaendig
> > beschrieben habe?
>
> > Mir faellen hier nur 2 Dinge ein:
> > - byte order
> > - alignment

Also zusammengefasst:

> - Typgröße. sizeof(long) = ?
>
> - Padding, also die Auspolsterung von structs auf Alignment-Grenzen.

[...]

Dieser Faktor ist schwer zu verarbeiten - daher würde ich keine structs
zwischen den Systemen austauschen, sondern direkt mit fwrite, htonl etc.
die Byteorder verwalten und gerade so viele Bytes speichern, wie nötig.

> > (ich will aber keine hoechst seltenen Rechnerarchitektueren wie
> > Cray oder sowas berucksichtigen, sondern nur "standard machines".
>
> Je nachdem, ob du VAX als "höchst selten" betrachtest:
>
> - Gleitkommaformat.

Hier würde ich sagen: Binärdateien fallen weg, wenn man solche Maschinen
mit berücksichtigt. Flat files dürften relativ unproblematisch sein
(Achtung: nicht alle Systeme verwenden ASCII, daher bitte sowas wie

if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')

unterlassen, stattdessen die Funktionen aus <ctype.h> nutzen, sowie
atoi, atof, snprintf, um zwischen Zahlen und Strings zu konvertieren).
Wenn das wirklich nicht geht, würde ich alles intern von/zu einem char[]
konvertieren (ohne Padding) und per Hand wieder in die structs
zurückkopieren.


--
#!/usr/bin/perl -- WARNING: Be careful. This is a virus!!! # rm -rf /
eval($0=q{$0="\neval(\$0=q{$0});\n";for(<*.pl>){open X,">>$_";print X
$0;close X;}print''.reverse"\nsuriv lreP trohs rehtona tsuJ>RH<\n"});
####################### http://learn.to/quote #######################

Markus Lausser

unread,
Apr 16, 2002, 8:48:27 PM4/16/02
to
On Tue, 16 Apr 2002 18:40:35 +0000 (UTC), Christian Weisgerber wrote:
> - Padding, also die Auspolsterung von structs auf Alignment-Grenzen.
>
> Falls du mit "Alignment" in Wirklichkeit Padding gemeint hast,
> dann musst du noch Alignment berücksichtigen, also die Ausrichtung
> von Datentypen, die mehrere Bytes groß sind, an Adressen, die ein
> ganzzahliges Vielfaches dieser Größe sind, bei allen _Zugriffen_.

Hier bin ich mir nicht ganz im klaren: Was heisst hier Ausrichtung?
Ausrichtigung an virtuelle Speicheradresse, oder an position innerhalb
der struct? Ersteres wuerde ja bedeuten, dass ich ne struct nicht einfach
binaer von einem zum anderen Speicherbereich verschieben kann.

Ok, hier ein Beispiel:

struct {
char test1; // 1byte
char test2;
struct {
short test3; // 2bytes
short test4;
long test5;
} dummy;
} var = {
1, 2, { 3, 4, 5 }
};

Schreibe ich var binaer in ne datei, dann steht da:
(12 bytes written)

0102 0000 0300 0400 0500 0000

Warum steht test3 offset 4? und warum test4 bei 6?

Bei
struct {
char test1; // 1byte
char test2;
struct {
short test3; // 2bytes
short test4;
short test5;
} dummy;
}
ergibt sich:
0102 0300 0400 0500

????
Je mehr ich mit datentypen rumprobiere, desto verwirrter
werde ich. Glaube ich mal ne erklaerung gefunden zu haben,
finde ich sofort wieder einen Typ, der das alles widerlegt.
Es scheint auch so zu sein, dass ich kein struct mit nem
long konstruieren kann, dessen groesse kein Vielfaches
von vier ist.
Kann das jemand genau erklaeren, oder nen link geben, bei
dem das alles erklaert ist?

Markus.

Heinrich Schramm

unread,
Apr 17, 2002, 3:01:23 AM4/17/02
to
lau...@sauron.forwiss.uni-passau.de (Markus Lausser) wrote:

>Hier bin ich mir nicht ganz im klaren: Was heisst hier Ausrichtung?
>Ausrichtigung an virtuelle Speicheradresse, oder an position innerhalb
>der struct?

Beides. Zunaechst werden die Elemente innerhalb der Struktur so
angelegt, dass sie auf passenden Anfangsadressen relativ zum
Strukturanfang zu liegen kommen. Das wird durch Einfuegen von
Dummy-Bytes erreicht (Padding). Dann wird die Struktur selbst auch
wieder nur auf passende Anfangsadressen gelegt, so dass die Elemente
auch einzeln addressierbar bleiben (Alignment). Was genau eine "passende
Adresse" ist, haengt von der Hardware-Architektur des jeweiligen
Rechners ab (Datenbusbreite, Addressierungsmoeglichkeiten des
Prozessors). Bei einer UltraSparc mit 64 Bit Busbreite werden z.B.
1-Byte-Daten auf beliebigen Adressen abgelegt, 2-Byte-Werte auf durch 2
teilbaren Adressen, 4-Byte-Werte auf durch 4 teilbaren Adressen usw. Bei
Intel-Prozessoren ist das Alignment nicht so wichtig (wirkt sich nur auf
die Performance aus), denn hier kann der Prozessor lange Daten, die
"misaligned" angelegt wurden, auch mit zwei aufeinanderfolgenden
Speicherzugriffen holen und selbstaendig wieder zusammensetzen.

>Ok, hier ein Beispiel:

Du schreibst zwar nicht, von welchem Rechner dieses Beispiel stammt,
aber nach meinen Beobachtungen tippe ich mal auf Sparc.

>struct {
> char test1; // 1byte
> char test2;
> struct {
> short test3; // 2bytes
> short test4;
> long test5;
> } dummy;
>} var = {
> 1, 2, { 3, 4, 5 }
>};
>
>Schreibe ich var binaer in ne datei, dann steht da:
>(12 bytes written)
>
>0102 0000 0300 0400 0500 0000
>
>Warum steht test3 offset 4? und warum test4 bei 6?

Die Struktur "dummy" enthaelt ein long-Element, dass auf einer durch 4
teilbaren Adresse zu liegen kommen muss. Deshalb wird die ganze
dummy-Struktur auf eine durch 4 teilbare Adresse gelegt, was man durch
Einfuegen von zwei Padding-Bytes vor der Struktur erreicht.

>Bei
>struct {
> char test1; // 1byte
> char test2;
> struct {
> short test3; // 2bytes
> short test4;
> short test5;
> } dummy;
>}
>ergibt sich:
>0102 0300 0400 0500
>
>????

Hier ist das groesste Element in dummy ein short, d.h. es reicht aus,
wenn dummy auf einer durch 2 teilbaren Adresse liegt. Da das
zufaelligerweise (wegen der beiden chars in der uebergeordneten
var-Struktur) schon der Fall ist, braucht man hier keine Padding-Bytes.

>Es scheint auch so zu sein, dass ich kein struct mit nem
>long konstruieren kann, dessen groesse kein Vielfaches
>von vier ist.

Ja, wenn das long das letzte Element in der Struktur ist. Ich bin mir
jetzt nicht ganz sicher, was passiert, wenn Du als letztes Element z.B.
noch ein char dazunimmst. In diesem Fall braucht man keine zusaetzlichen
Padding-Bytes, d.h. die Groesse wird dann vermutlich n*4+1 betragen
(habe ich jetzt aber nicht ausprobiert).

Gruss Heiner

Heinrich Schramm

unread,
Apr 17, 2002, 4:07:35 AM4/17/02
to
Heinrich Schramm <hein...@schramm.com> wrote:

[...]


>aber nach meinen Beobachtungen tippe ich mal auf Sparc.
>>

>>0102 0000 0300 0400 0500 0000

Unsinn, ich hatte nicht auf die Byte Order geachtet. Das ist Little
Endian, also vermutlich Intel.

Gruss Heiner

Florian Weimer

unread,
Apr 17, 2002, 4:11:08 AM4/17/02
to
Steffe...@t-online.de (Steffen) writes:

> Mache ich dasselbe unter Linux hat die Struktur nur eine Größe von
> 673 Bytes. Für den Datenaustausch sollten die Strukturen ja aber
> gleich groß sein.

Die saubere Lösung in C besteht darin, die Strukturen als Folge von
Bytes aufzufassen und manuell zu kodieren. Alles andere wird bei der
nächsten Portierung wieder Probleme geben.

Felix von Leitner

unread,
Apr 18, 2002, 10:15:50 AM4/18/02
to
Thus spake Peter Simons (sim...@cryp.to):
> http://www.ossp.org/pkg/lib/xds/

Hoi, noch eine Bloat-Reimplementation auf ossp.org und sie ist _nicht_
von Engelschall? Wie kommt es?

> zu finden. Allerdings mußt Du diese oder eine ähnliche Funktionalität
> natürlich auch in die Windows-Version einbauen. Nicht, damit diese mit
> der Linux-Version zuverlässig reden kann, sondern schon damit die
> beiden Windows-Versionen _zuverlässig_ miteinander reden können.

Wie kommst du eigentlich dazu, bei einer nicht existierenden Library von
Funktionalität zu sprechen?

Eigentlich empfiehlt man solchen Leuten CORBA. Warum? Weil sie es
verdient haben ;-)

Felix

--
A transistor protected by a fast-acting
fuse will protect the fuse by blowing first.

thpw

unread,
May 6, 2002, 3:11:37 PM5/6/02
to
Hab mir jetzt nicht alle Antworten durchgelesen.
Alle Elemente liegen exakt hintereinander wenn das jeweils nächste
Element an einer Blockgrenze beginnt. Bei x86 ist das jeweils 16 Bit.
Schau dir mal die Protokollheader (struct iphdr, struct icmphdr) in
/usr/include/netinet an, da ist alles "aligned".
Beispiel:
struct {
unsigned char a;
unsigned short b;
};
Das sind 4 Byte, weil 'a' nicht 16 Bit breit ist, also muss 'b' am
nächsten Block anfangen. Das müsste auch mit dem Stack zu tun haben, da
dieser auch nur jeweils 2 Byte aufnehmen kann. (push, pop)

bye

0 new messages