Delen via


Problemen met het verpakken van C-compiler

Verpakkingsniveaus zijn van invloed op de geheugenindeling van typen voor zowel MIDL als de Microsoft C/C++-compiler op dezelfde manier. In Microsoft-buildomgevingen, zoals de buildomgeving die is gedefinieerd door VC++ of de Platform Software Development Kit (SDK), is het standaardverpakkingsniveau voor MIDL- en C/C++-compilers hetzelfde; het standaardverpakkingsniveau voor de 32-bits en 64-bits Windows-buildomgevingen is 8.

Natuurlijke uitlijning

Voor typen geheugen is de standaarduitlijning hetzelfde als de natuurlijke uitlijning.

  • Een basistype, zoals short, float en __int64, en een aanwijzer wordt natuurlijk uitgelijnd als de weergave begint bij een adres dat modulo de grootte ervan is. Alle momenteel ondersteunde basistypen hebben een grootte van 1, 2, 4 of 8. Aanwijzers hebben een grootte van 4 in 32-bits omgevingen en 8 in 64-bits omgevingen.
  • Een samengesteld type wordt natuurlijk uitgelijnd als elk van de onderdelen op natuurlijke wijze is uitgelijnd ten opzichte van het begin van het type en als er geen onnodige hiaten (opvulling) tussen onderdelen zijn. Samengestelde onderdelen, zoals velden of elementen, worden teruggezet naar aanwijzer- of basistypeonderdelen.

Een eenvoudige regel om dit gedrag te onthouden, is dat de natuurlijke uitlijning van een type gelijk is aan de grootste uitlijning van de onderdelen.

Er is een verbinding tussen uitlijning en geheugengrootte van een type talen zoals C of C++ en IDL, uitgedrukt door de operator groottevan(). De grootte is een veelvoud van de uitlijning (het minimale veelvoud dat het type overspant). Dit volgt uit een matrixweergave in het geheugen.

Natuurlijke uitlijning is belangrijk omdat het openen van verkeerd uitgelijnde gegevens een uitzondering op sommige systemen kan veroorzaken. Gegevens kunnen worden gemarkeerd voor een veilige manipulatie wanneer ze verkeerd zijn uitgelijnd, maar meestal met een snelheidsstraf die op sommige platforms aanzienlijk kan zijn.

Notitie

In het geheugen worden objecten van typen met een natuurlijke uitlijning van n gegarandeerd correct uitgelijnd wanneer ze worden geplaatst op adressen die een veelvoud van nzijn.

 

Verpakking versus uitlijning

Als u een verpakkingsniveau opgeeft dat groter is dan de natuurlijke uitlijning van een type, wordt de typeuitlijning niet gewijzigd. Als u een verpakkingsniveau opgeeft dat kleiner is dan de natuurlijke uitlijning, wordt de typeuitlijning verminderd tot het verpakkingsniveau. Als gevolg hiervan kunnen de verpakte typen in het geheugen worden geplaatst op adressen die een veelvoud van het verpakkingsniveau (de verminderde uitlijning) zijn zonder verkeerde uitlijning te veroorzaken. Dit is van invloed op zowel eenvoudige typen als onderdeeltypen. Voor samengestelde typen kan de interne indeling van het type worden beïnvloed, omdat de verminderde uitlijning van de onderdelen de grootte van de opvulling kan wijzigen die nodig is voor de juiste uitlijning van de onderdelen, waardoor de grootte van het type wordt verkleind.

Een eenvoudige regel om dit gedrag te onthouden, is dat de nieuwe uitlijning van een ingepakt type het kleinste is van het verpakkingsniveau en de natuurlijke uitlijning. De grootte van het type is een veelvoud van de nieuwe uitlijning. De operator sizeof() geeft de verminderde grootte voor verpakte typen.

Bijvoorbeeld, met verpakkingsniveau 2 wordt een long uitgelijnd op 2, en kan daarom op elk even adres worden geplaatst, niet alleen op de adressen die een veelvoud van 4 zijn, zoals het geval zou zijn bij natuurlijke uitlijning. Een structuur met een korte en een lange component, verpakt volgens 2, heeft niet de interne tussenruimte nodig tussen de korte en de volgende lange zoals dat nodig was voor de natuurlijke uitlijning. Daarom is de structuur niet alleen nu uitgelijnd op 2, maar is ook zijn grootte verminderd van 8 naar 6.

Denk bijvoorbeeld aan een samengesteld type dat bestaat uit een teken van 1 byte, een geheel getal van 4 bytes lang en een teken van 1 byte:

struct mystructtype 
{    
    char c1;  /* requires 1 byte  */
              /* 3 bytes of padding with natural alignment only */
    long l2;  /* requires 4 bytes */
    char c3;  /* requires 1 byte  */
              /* 3 bytes of padding with natural alignment only */
 } mystruct;

Deze structuur is van nature uitgelijnd op 4 en heeft een natuurlijke omvang van 12.

Voor een verpakkingsniveau van 4 of hoger wordt de structuur mystruct uitgelijnd op niveau 4 en is sizeof(struct mystructtype) gelijk aan 12. De structuur wordt verkeerd uitgelijnd als deze zich in het geheugen bevindt op een adres dat geen veelvoud is van 4.

Voor verpakkingsniveau 2 wordt de structuur uitgelijnd op 2 en de grootte is 8. De structuur met niveau 2 wordt verkeerd uitgelijnd als deze zich in het geheugen bevindt op een adres dat geen veelvoud van 2 is.

Voor verpakkingsniveau 1 wordt de structuur uitgelijnd op 1 en de grootte is 6. De structuur met level 1 kan overal worden geplaatst zonder een uitlijningsfout te veroorzaken.

/Zp

/pack