Toon posts:

[c] packed structures

Pagina: 1
Acties:

Verwijderd

Topicstarter
Na een tijdje zoeken ben ik er nu eindelijk achter gekomen hoe ik een packed c-structure kan maken. Dus een structure waarvan de members niet aligned zijjn. Dit is bijvoorbeeld handing bij het inlezen van binaire bestanden.

onder gcc gebruik ik het volgende:
C:
1
2
3
4
5
6
7
8
struct msdib_file_header
{
  char bf_type[2] __attribute__ ((packed));
  unsigned int bf_size __attribute__ ((packed));
  unsigned short bf_reserved0  __attribute__ ((packed));
  unsigned short bf_reserved1  __attribute__ ((packed));
  unsigned int bf_off_bits __attribute__ ((packed));
};
(irrelevant, maar dit is de file header van een MS-DIB, als ik deze unpacked inlees krijg ik redelijk verstrooide data terug)

Maar ik heb begrepen dat __attribute__ ((packed)) specefiek voor de gcc compiler is..

Weet iemand of er een compiler onafhankelijke methode is om packed structures te maken? Ik kan er weinig over vinden. Het liefst zo ik met een regel een complete struct packed maken en het niet bij elke member op geven.

Ik werk overigens wel met gcc (onder linux) maar wil mijn source zo platform/ciompiler onafhankelijk houden als mogelijk.

[ Voor 29% gewijzigd door Verwijderd op 10-12-2002 12:39 ]


Verwijderd

#pragma pack (1) :?

Verwijderd

Topicstarter
Is dat niet C++? Ik heb het hier echt over C.

EDIT: Thanks, dit werkt inderdaad zonder enig probleem onder C!

[ Voor 69% gewijzigd door Verwijderd op 10-12-2002 12:44 ]


  • matthijsln
  • Registratie: Augustus 2002
  • Laatst online: 30-07 16:33
#include ...

#pragma pack(push,1)

... hier je struct declaraties...

#pragma pack(pop)

De meeste compilers ondersteunen dit geloof ik wel, en het is wat minder waarschijnlijk dat het andere code breekt.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 10:46

.oisyn

Moderator Devschuur®

Demotivational Speaker

#pragma pack () is niet standaard, geen enkele #pragma is standaard, daar is #pragma ook voor bedoeld :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
Het mag dan niet standaard zijn (wel jammer) het is in ieder geval netter dan __attribute__ ((packed) achter elke member plakken. Als ik het ooit ga porten zie ik wel hoe ik het aanpak....

  • JeroenB
  • Registratie: November 1999
  • Laatst online: 10-07 20:20
Met de Microsoft C/C++ compiler kan je /Zpn als commandline optie meegeven, waarbij n de alignment is (bijv. 1 of 2.)

Overigens werkt de #pragma pack-methode ook met deze compiler, dus lijkt het me de beste methode om het zoveel mogelijk portable te houden.

Verwijderd

Je kunt natuurlijk ook een macro schrijven die het werk voor je doet, waarbij je in een speciale headerfile dit macro defineerd aan de hand van de gebruikte compiler (met #ifdef'jes).
Het is overigens nogal buggy dat je "int" gebruikt in de struct, dit kan een long of een short zijn, hier moet je wel specifieker zijn, kan ook een veroorzaker van problemen worden...

(hmm: pragma's gebruiken voor portabiliteit :? )

Trouwens dit was zowiezo veel makkelijker geweest en levert volgens mij hetzelfde resultaat:
C:
1
2
3
4
5
6
7
8
struct  __attribute__ ((packed)) msdib_file_header
{
  char bf_type[2];
  unsigned int bf_size;
  unsigned short bf_reserved0;
  unsigned short bf_reserved1;
  unsigned int bf_off_bits;
};

[ Voor 45% gewijzigd door Verwijderd op 10-12-2002 14:54 ]


Verwijderd

#pragma pack is de slechtst mogelijke manier om binnen een compiler packing te implementeren. Als je een pack-attribute implementeert (zoals in gcc), loop je nooit kans dat iemand per ongeluk structs/enums in een andere header ook meepackt. Met een pragma moet je allerlei moeilijke clauses zoals push/pop en enter_include introduceren om dit soort fouten te voorkomen. Dat is natuurlijk minder eenvoudig dan een attribute waarmee het niet fout kan gaan. Pragma's in een compiler zijn gewoon XXX, en packing pragma's mogen nog een Xje extra..

  • JeroenB
  • Registratie: November 1999
  • Laatst online: 10-07 20:20
mietje: Ten eerste kun je het gebied waarbinnen die #pragma werkt afbakenen en daarnaast kan er niet zo ontzettend veel misgaan met packing tenzij je ranzige code schrijft :)

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
char[] gebruiken, zelf decoden.
Er kan feitelijk geen portable methode gemaakt worden. omdat sommige processoren eenvoudigweg geen packed int kunnen lezen.

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


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

JeroenB schreef op 10 december 2002 @ 14:10:
Met de Microsoft C/C++ compiler kan je /Zpn als commandline optie meegeven, waarbij n de alignment is (bijv. 1 of 2.)
En dit wil je dus nooit omdat je applicatie er structureel trager van wordt. Het kan alleen zijn dat je een of meerdere specifieke structs die je voor specifieke toepassingen gebruikt op een andere pack-size wil hebben, en daarvoor gebruik je dan netjes zoals matthijsln aangeeft de push/pop methods om niet met globale definities te interfereren: als je dit namelijk in een header zonder push/pop doet kan het zijn dat de volgende include in de lijst in de ene CPP een andere pack-size heeft dan in een andere, en dat is een leuke bron voor onvindbare segfaults/access violations.

Professionele website nodig?


Verwijderd

JoeroenB: met _attribute__ ((packed)) kan het nooit mis gaan. Bij #pragma pack zijn er verschillende manieren waarop het fout kan gaan. Met de attribute hoef je als programmeur dus verder nergens rekening mee te houden, met de pragma wel. Het simpele feit dat er opties zijn om de werking van die pragma te beperken bewijst dat. QED.

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

MSalters schreef op 10 december 2002 @ 14:50:
char[] gebruiken, zelf decoden.
Er kan feitelijk geen portable methode gemaakt worden. omdat sommige processoren eenvoudigweg geen packed int kunnen lezen.
Bitfields zijn onderdeel van ANSI-C en dus 100% portable met de goede ifdef's eromheen op bytegrootte :)

Portable in deze tijd slaat echter voor de hobbyist en ook de meeste pro's meer op verschillende OS'en en compilers dan op verschillende CPU-families... ja hier hebben we mekaar eerder over in de haren gezeten maar het is wel zo ;)

Professionele website nodig?


  • JeroenB
  • Registratie: November 1999
  • Laatst online: 10-07 20:20
mietje: Dat betwist ik helemaal niet, waar het om gaat is wat de poster vroeg. Die had de _attribute__ ((packed)) methode al gevonden en vroeg of het op een meer portable manier kon. Ik heb nooit geclaimed dat het slim zou zijn om de #pragma-methode te gebruiken alleen de beste mbt portabiliteit. Dat stabiliteit aanvankelijker of uberhaupt belangrijker is dan portabiliteit hebben we het helemaal niet over gehad en heb ik dus ook geen uitspraak over gedaan.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 10:46

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op 10 December 2002 @ 14:53:
JoeroenB: met _attribute__ ((packed)) kan het nooit mis gaan. Bij #pragma pack zijn er verschillende manieren waarop het fout kan gaan. Met de attribute hoef je als programmeur dus verder nergens rekening mee te houden, met de pragma wel. Het simpele feit dat er opties zijn om de werking van die pragma te beperken bewijst dat. QED.


ja, en met pointers kun je vervelende dingen doen. Is dat een reden om geen pointers te gebruiken? Vind het een beetje een onzin beargumentering eigenlijk. Als je gewoon netjes je pack declaraties strak om je struct heen doet dan kan er niets misgaan.

Een programmeertaal hoeft niet foolproof te zijn, en als je dat toch nodig hebt moet je gewoon niet gaan programmeren

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

.oisyn: Het argument is dat er twee verschillende constructs mogelijk zijn om te packen:
1) #pragma pack
2) __attribute__ ((packed))
Met beide constructs bereik je precies het zelfde: packed structs/unions. Nu is 2) foolproof en 1) niet, terwijl ze de zelfde functionaliteit hebben (eigenlijk niet, je kunt meer met 2)). Als jij een compiler moet schrijven, voor welke construct kies jij dan?

  • JeroenB
  • Registratie: November 1999
  • Laatst online: 10-07 20:20
mietje: De vraag ging over portabiliteit tussen platforms en compilers. De discussie die je start is dus off-topic.

Verwijderd

Verwijderd schreef op 10 December 2002 @ 15:46:
.oisyn: Het argument is dat er twee verschillende constructs mogelijk zijn om te packen:
1) #pragma pack
2) __attribute__ ((packed))
Met beide constructs bereik je precies het zelfde: packed structs/unions.
Wil je portabiliteit dan kun je geen van tweeen gebruiken mijns inziens, dan kun je beter een macro introduceren in een headerfile die je standaard include, net zoals je die ook nodig zal hebben om bepaalde bit-sizes te garanderen, want een int is niet altijd 16 of 32, een long niet altijd 32, enz.,enz, terwijl er in een packed struct absolute garantie moet zijn over de bitsizes van elke struct-member...

Verwijderd

Topicstarter
Verwijderd schreef op 10 december 2002 @ 14:11:
Het is overigens nogal buggy dat je "int" gebruikt in de struct, dit kan een long of een short zijn, hier moet je wel specifieker zijn, kan ook een veroorzaker van problemen worden...
True. Ik was mezelf net aan het aanleren zoveel mogelijk int te gebruiken om zo architectuur onafhankelijk te zijn, het laat zich dan ook netjes op een 16 of 64 bit bak compileren. Maar in dit soort implementaties waar je verplicht bent een 32 bit waarde uit te lezen kan het idd problemen veroorzaken.

Verwijderd

Probleem is dat je geen macro kunt bedenken die de verschillende constructs onder een noemer brengt. De vraag is dus al beantwoord: het kan niet portable.

Verwijderd

Topicstarter
mietje: ik snap jouw waarschuwing voor het gevaar van een pragma niet.
indien ik deze code neerzet...
C:
1
2
3
4
5
6
7
8
9
10
#pragma pack (1)
struct msdib_file_header
{
  char bf_type[2];
  unsigned int bf_size;
  unsigned short bf_reserved0;
  unsigned short bf_reserved1;
  unsigned int bf_off_bits;
};
#pragma pack (0)
... dan kan er toch praktisch niets misgaan?

[ Voor 5% gewijzigd door Verwijderd op 10-12-2002 16:16 ]


Verwijderd

Verwijderd schreef op 10 december 2002 @ 16:16:
mietje: ik snap jouw waarschuwing voor het gevaar van een pragma niet.
indien ik deze code neerzet...
... dan kan er toch praktisch niets misgaan?
Voor zover ik weet is #pragma zo gedefineerd dat een compiler-specifieke control is en dat een andere compiler vrolijk door mag fluiten als 'ie een pragma niet herkent, omdat het dan blijkbaar voor een andere compiler is bedoelt... Dus dat is niet zo foolproof in dat geval, dan denk je dat het gepacked is als je de code leest, maar in werkelijkheid is dit niet het geval...

edit:
TBD


Maar volgens mij ondersteunen toch wel de meeste compiler een soort attribuut op een struct om deze te packen, net zoals je dus ook "struct __attribute__((__packed__)) msdib_file_header { ... };" in gcc kunt doen... Je hoeft dit voor gcc echt niet per structmember te doen.

[ Voor 21% gewijzigd door Verwijderd op 10-12-2002 16:46 ]


Verwijderd

Topicstarter
struct __attribute__((__packed__)) msdib_file_header { ... }; liet zich bij mij niet compileren.

Verwijderd

Verwijderd schreef op 10 December 2002 @ 16:44:
struct __attribute__((__packed__)) msdib_file_header { ... }; liet zich bij mij niet compileren.
Als ja dat maar niet letterlijk zo hebt ingetikt... ;)

Bij mij werkt het in ieder geval wel met gcc 2.95.4, even snel ook getest en met gcc-3.0.4 en dat werkte ook (maar dan met structmembers uiteraard).

[ Voor 6% gewijzigd door Verwijderd op 10-12-2002 16:51 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 10:46

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op 10 December 2002 @ 15:46:
.oisyn: Het argument is dat er twee verschillende constructs mogelijk zijn om te packen:
1) #pragma pack
2) __attribute__ ((packed))
Met beide constructs bereik je precies het zelfde: packed structs/unions. Nu is 2) foolproof en 1) niet, terwijl ze de zelfde functionaliteit hebben (eigenlijk niet, je kunt meer met 2)). Als jij een compiler moet schrijven, voor welke construct kies jij dan?


de vraag was of er een portable manier was, die is er dus niet. Met MSVC++ bijvoorbeeld heb je geen attribute specifier, en dus zul je het met de pragma moeten doen.
Echter, wat die keuze betreft, de #pragma pack () wordt door veel meer compilers ondersteund dan gcc's __attribute__ specifier, ik zou dus voor de pragma gaan

Ik zie trouwens niet in hoe optie 2 meer kan dan optie 1... lijkt me eerder andersom, met de 2e kun je namelijk alleen per declaratie vaststellen dat ie gepacked moet worden. Met de 1e optie kun je ook nog eens opgeven HOE ie gepacked moet worden (1 byte, 2 bytes, 4 bytes, ...), en je kunt ook meerdere structs in 1 keer doen
Verwijderd schreef op 10 December 2002 @ 16:08:
Probleem is dat je geen macro kunt bedenken die de verschillende constructs onder een noemer brengt. De vraag is dus al beantwoord: het kan niet portable.
je kunt natuurlijk wel meerdere macro's gebruiken
Verwijderd schreef op 10 December 2002 @ 16:16:
mietje: ik snap jouw waarschuwing voor het gevaar van een pragma niet.
indien ik deze code neerzet...
C:
1
2
3
4
5
6
7
8
9
10
#pragma pack (1)
struct msdib_file_header
{
  char bf_type[2];
  unsigned int bf_size;
  unsigned short bf_reserved0;
  unsigned short bf_reserved1;
  unsigned int bf_off_bits;
};
#pragma pack (0)
... dan kan er toch praktisch niets misgaan?
toch wel, met pack (0) zet je de pack waarde weer op de default (dus waar ie op stond toen ie begon met compilen), bijvoorbeeld 4, terwijl daarvoor misschien wel een #pragma pack(2) stond. Werk dus altijd met push/pop constructies

Overigens vind ik het wel een slechte manier van coden als je de #pragma's niet strak om je struct zet, juist om de reden die mietje aanhaalt. Dus niet na zo'n pragma een file gaan includen, en altijd weer de juiste packing waarde terug zetten zodra je ermee klaar bent

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

.oisyn schreef op 10 december 2002 @ 16:56:
Ik zie trouwens niet in hoe optie 2 meer kan dan optie 1
C:
1
2
3
4
5
struct blah {
    short x __attribute__ ((packed));
    short y __attribute__ ((packed));
    double unpacked;
};


edit:
En packen is iets anders dan alignen...

Alignen op 4 bytes: __attribute__ ((aligned(4)))

[ Voor 16% gewijzigd door Verwijderd op 10-12-2002 17:15 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 10:46

.oisyn

Moderator Devschuur®

Demotivational Speaker

dat kan met #pragma pack () natuurlijk ook :)

C++:
1
2
3
4
5
6
7
8
struct Test
{
#pragma pack (push, 1)
    short s;
    int i1;
#pragma pack (pop)
    int i2;
};

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Hmm, mja, binnen een structdecl kan? Lelijk iig ;)

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Verwijderd schreef op 10 december 2002 @ 16:08:
Probleem is dat je geen macro kunt bedenken die de verschillende constructs onder een noemer brengt. De vraag is dus al beantwoord: het kan niet portable.
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Dit in een root-header, en nee niet alle predefined macros kloppen maar geen
// zin om ze op te zoeken   :-)
#if defined(__BORLANDC__) || defined(__MSVCVER__)
  #define BeginPackedStructBlock(p_Size) #pragma pack(push, p_Size)
  #define EndPackedStructBlock #pragma pack(pop)
  #define PACKEDATTRIBUTE
#elif defined(__GCC__)
  #define BeginPackedStructBlock(p_Size)
  #define EndPackedStructBlock
  #define PACKEDATTRIBUTE __attribute__ ((packed))
#else
  #error Structure packing macros not defined for current compiler
#endif

// En dan dit in de reguliere headers
BeginPackedStructBlock(1)
  struct msdib_file_header 
  { 
  char bf_type[2] PACKEDATTRIBUTE; 
  unsigned int bf_size PACKEDATTRIBUTE; 
  unsigned short bf_reserved0 PACKEDATTRIBUTE; 
  unsigned short bf_reserved1 PACKEDATTRIBUTE; 
  unsigned int bf_off_bits PACKEDATTRIBUTE; 
  };
EndPacketStructBlock

Professionele website nodig?


Verwijderd

/me ...en Curry684 neemt ook elke uitdaging aan ;)

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Verwijderd schreef op 10 December 2002 @ 18:02:
/me ...en Curry684 neemt ook elke uitdaging aan ;)
Na 20 posts gezwets in de ruimte had ik pas tijd om even in te springen ;)

Ik zou zelf trouwens voor kortere en krachtigere macronamen kiezen, maar zo komt het concept tenminste door.

Professionele website nodig?


Verwijderd

curry>> en dan nu zodat BeginPackedStructBlock(2) ook werkt onder GCC...

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 10:46

.oisyn

Moderator Devschuur®

Demotivational Speaker

das miereneukerij natuurlijk, dan kun je net zo goed die size niet verkiesbaar maken en dus standaard op 1 houden

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

/me zucht.

Als ik aantoon dat het niet kan (omdat een pragma een context heeft en een attribute contextvrij is), is het miereneukerij...

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 10:46

.oisyn

Moderator Devschuur®

Demotivational Speaker

nee, het is mierenneukerij omdat je met __attribute__ ((packed)) helemaal geen grootte van 2 op kunt geven, en dat weet jij ook wel

en het ging ook helemaal niet om groottes anders dan 2, het ging om een generieke manier om de structs zo gepacked mogelijk te krijgen (1 dus)

[ Voor 36% gewijzigd door .oisyn op 10-12-2002 18:27 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

.oisyn schreef op 10 December 2002 @ 18:27:
nee, het is mierenneukerij omdat je met __attribute__ ((packed)) helemaal geen grootte van 2 op kunt geven, en dat weet jij ook wel
Zoals ik al aangaf gebruik je daar __attribute__ ((aligned(x))) voor. (Packen is niet alignen; packen is net unalignen.)

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Verwijderd schreef op 10 December 2002 @ 18:21:
curry>> en dan nu zodat BeginPackedStructBlock(2) ook werkt onder GCC...
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Dit in een root-header, en nee niet alle predefined macros kloppen maar geen 
// zin om ze op te zoeken   :-) 
#if defined(__BORLANDC__) || defined(__MSVCVER__) 
  #define BeginPackedStructBlock(p_Size) #pragma pack(push, p_Size) 
  #define EndPackedStructBlock #pragma pack(pop) 
  #define PACKEDATTRIBUTE 
#elif defined(__GCC__) 
  #define BeginPackedStructBlock(p_Size)   #define PackSize p_Size
  #define EndPackedStructBlock 
  #define PACKEDATTRIBUTE __attribute__ ((aligned(p_Size), packed))
#else 
  #error Structure packing macros not defined for current compiler 
#endif 

// En dan dit in de reguliere headers 
BeginPackedStructBlock(1) 
  struct msdib_file_header  
  {  
  char bf_type[2] PACKEDATTRIBUTE;  
  unsigned int bf_size PACKEDATTRIBUTE;  
  unsigned short bf_reserved0 PACKEDATTRIBUTE;  
  unsigned short bf_reserved1 PACKEDATTRIBUTE;  
  unsigned int bf_off_bits PACKEDATTRIBUTE;  
  }; 
EndPacketStructBlock

Professionele website nodig?


Verwijderd

__attribute__ ((aligned(2), pack)) is niet het zelfde als __attribute__ ((aligned(2))).

Anyway, dit gaat wel erg ver offtopic langzaam.

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Verwijderd schreef op 10 December 2002 @ 18:39:
__attribute__ ((aligned(2), pack)) is niet het zelfde als __attribute__ ((aligned(2))).
Klopt zoals u al zei:
(Packen is niet alignen; packen is net unalignen.)
Gecombineerd is het packen tot de betreffende precisie.

Professionele website nodig?


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 10:46

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op 10 december 2002 @ 18:39:
__attribute__ ((aligned(2), pack)) is niet het zelfde als __attribute__ ((aligned(2))).


klopt, maar het ging toch juist om het packen, niet alleen om het alignen? dus het is nu goed zo imho

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1