Toon posts:

[C]struct alignment

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik ben bezig met een stukje Linux C code (moet later ook nog geport worden naar Windows). Als een struct niet een veelvoud van de grootte van een int bevat, wordt deze toch op de int-boundaries uitgelijnd (en sizeof geeft een veelvoud van de grootte van een int terug).
Dit wordt gedaan omdat de pointer-berekeningen dan veel 'makkelijker' zijn.

In mijn programma is dat erg lastig omdat de communicatie protocollen die ik gebruik daar niet van houden (ik gebruik bv een 10-byte header) en het verder portability naar 64-bit processoren (in de toekomst) in de weg staat.
Ik weet vrijwel zeker dat er ergens een vlag of een define is die ervoor zorgt dat dit niet gebeurt, maar kan het ding niet vinden.

[ Voor 16% gewijzigd door Verwijderd op 26-03-2003 06:32 ]


Verwijderd

Topicstarter
Oplossing gevonden (blijkbaar niet goed genoeg gezocht) :z Oplossing zit in __attribute__ ((packed))
code:
1
2
3
4
5
typedef struct AB
{
int a;
short int b;
} __attribute__ ((packed)) sAB;

  • windancer
  • Registratie: Maart 2000
  • Laatst online: 18-08 22:36
Verwijderd schreef op 26 March 2003 @ 06:29:
... Als een struct niet een veelvoud van de grootte van een int bevat, wordt deze toch op de int-boundaries uitgelijnd (en sizeof geeft een veelvoud van de grootte van een int terug)...
sizeof geeft een veelvoud van de grootte van char terug, niet van int.

Verwijderd

Topicstarter
In de gegeven code (en je laat het packed attribuut weg) geeft sizeof 4 terug (op een 32-bit systeem). Dat is een veelvoud van de grootte van een int (namelijk het eerste veelvoud).

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
Als je wilt porten, dan is __attribute__ niet bruikbaar (net zoals bijna alle namen met __ erin, eigenlijk alleen __FILE__ en __LINE__ ).

De correcte oplossing is zelf een generieke leesroutine schrijven die 10 unsigned chars leest, en weet wat er in staat. Jouw voorbeeld met ((packed)) gaat bijvoorbeeld al four op de door jou genoemde 64-bits systemen; daar kan de structure opeens 96 bits zijn ipv 48 nu. Had je gewoon (1<<24 * eerste byte +... + laatste byte) geassigned, dan was van je 64-bits int de bovenste helft ongebruikt geweest, maar was de code nog steeds correct.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • igmar
  • Registratie: April 2000
  • Laatst online: 16:57

igmar

ISO20022

Verwijderd schreef op 26 March 2003 @ 06:49:
Oplossing gevonden (blijkbaar niet goed genoeg gezocht) :z Oplossing zit in __attribute__ ((packed))
code:
1
2
3
4
5
typedef struct AB
{
int a;
short int b;
} __attribute__ ((packed)) sAB;
Als alternatief kun je -fpack-struct gebruiken. Is het niet veel handiger om je struct te null-padden op 4 bytes sizes ?? Veel architecturen vinden het absoluut niet leuk als je niet op 4 byte boundaries leest.

Ik zou zeker voor de __attribute__ optie gaan, en desnoods overgaan tot #define s

Verwijderd

Topicstarter
MSalters schreef op 26 maart 2003 @ 09:49:
Als je wilt porten, dan is __attribute__ niet bruikbaar (net zoals bijna alle namen met __ erin, eigenlijk alleen __FILE__ en __LINE__ ).

De correcte oplossing is zelf een generieke leesroutine schrijven die 10 unsigned chars leest, en weet wat er in staat. Jouw voorbeeld met ((packed)) gaat bijvoorbeeld al four op de door jou genoemde 64-bits systemen; daar kan de structure opeens 96 bits zijn ipv 48 nu. Had je gewoon (1<<24 * eerste byte +... + laatste byte) geassigned, dan was van je 64-bits int de bovenste helft ongebruikt geweest, maar was de code nog steeds correct.
Tav porten heb je gelijk; onder QNX heet het volgens mij gewoon packed struct (of zoiets; meen ik me te herinneren).
Verder heb je gelijk wat betreft de 48/96; zal daar nog even wat verder op studeren. Een int wordt (zeer vermoedelijk) groter in een 64-bit systeeem, maar geldt dat ook voor een short int; zal vermoedelijk short maar eens gaan vervangen door int16_t of zo.
igmar schreef op 26 March 2003 @ 11:14:
[...]


Als alternatief kun je -fpack-struct gebruiken. Is het niet veel handiger om je struct te null-padden op 4 bytes sizes ?? Veel architecturen vinden het absoluut niet leuk als je niet op 4 byte boundaries leest.

Ik zou zeker voor de __attribute__ optie gaan, en desnoods overgaan tot #define s
"Probleem' is dat de data binnenkomt als een stream van bytes (netwerk, serieel). Wat is er dan handiger om dit te casten naar de struct. Dit gaat niet als je gaat padden. Dan moet je weer allerlei trucs gaan uithalen met memcpy.

==================
Iedereen bedankt voor de reacties.

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22-08 01:56
Wat betreft portabiliteit: sommige hardwarearchitecturen vereisen aligned data en daarop worden dus geen packed structs ondersteund. Dan zul je toch echt met memcpy aan de slag moeten (aangezien assignment op basis van casts dan ook niet werkt). Een universele efficiente oplossing bestaat er niet, vrees ik. Je zult toch al ingewikkelde constructies moeten verzinnen om te compenseren voor verschillen in endianess (tenzij je geen communicatie tussen verschillende architecturen ondersteunt).

Ik dacht trouwens dat elke struct member op zijn eigen grootte gealigned wordt (dus een 'int' op een 4-byte boundary, char gewoon op een 1-byte boundary, double op 8-byte boundary, etcetera). Bij het ontwerpen van bestandsformaten kun je daar dus al rekening mee houden, door bijvoorbeeld een struct niet uit achtereenvolgens "char, char, int, char, char" samen te stellen, maar bijvoorbeeld "char, char, char, char, int". Aangezien die members een naam hebben, maakt het voor de rest van de code eigenlijk niet uit (al blijft 't een beetje hacken, natuurlijk).

[ Voor 37% gewijzigd door Soultaker op 26-03-2003 12:54 ]

Pagina: 1