C++
Layout av objekttyper
Sök…
Anmärkningar
Se även storlek på integrerade typer .
Klasstyper
Med "klass" menar vi en typ som definierades med hjälp av sökordet class
eller struct
(men inte enum struct
eller enum class
).
Även en tom klass upptar fortfarande minst en byte av lagring; den kommer därför att bestå enbart av stoppning. Detta säkerställer att om
p
pekar på ett objekt i en tom klass, så ärp + 1
en distinkt adress och pekar på ett distinkt objekt. Det är dock möjligt för en tom klass att ha storleken 0 när den används som basklass. Se tom basoptimering .class Empty_1 {}; // sizeof(Empty_1) == 1 class Empty_2 {}; // sizeof(Empty_2) == 1 class Derived : Empty_1 {}; // sizeof(Derived) == 1 class DoubleDerived : Empty_1, Empty_2 {}; // sizeof(DoubleDerived) == 1 class Holder { Empty_1 e; }; // sizeof(Holder) == 1 class DoubleHolder { Empty_1 e1; Empty_2 e2; }; // sizeof(DoubleHolder) == 2 class DerivedHolder : Empty_1 { Empty_1 e; }; // sizeof(DerivedHolder) == 2
Objektrepresentationen av en klasstyp innehåller objektrepresentationen av basklassen och icke-statiska medlemstyper. Därför till exempel i följande klass:
struct S { int x; char* y; };
det finns en i följd sekvens av
sizeof(int)
byte i ettS
objekt, kallat ett subobjekt, som innehåller värdet påx
, och ett annat subobjekt medsizeof(char*)
byte som innehåller värdet påy
. De två kan inte läggas samman.Om en klasstyp har medlemmar och / eller basklasser med typerna
t1, t2,...tN
, måste storleken vara minstsizeof(t1) + sizeof(t2) + ... + sizeof(tN)
med de föregående punkterna . Beroende på anpassningskraven för medlemmarna och basklasserna kan kompilatorn emellertid tvingas införa stoppning mellan underobjekt eller i början eller slutet av det kompletta objektet.struct AnInt { int i; }; // sizeof(AnInt) == sizeof(int) // Assuming a typical 32- or 64-bit system, sizeof(AnInt) == 4 (4). struct TwoInts { int i, j; }; // sizeof(TwoInts) >= 2 * sizeof(int) // Assuming a typical 32- or 64-bit system, sizeof(TwoInts) == 8 (4 + 4). struct IntAndChar { int i; char c; }; // sizeof(IntAndChar) >= sizeof(int) + sizeof(char) // Assuming a typical 32- or 64-bit system, sizeof(IntAndChar) == 8 (4 + 1 + padding). struct AnIntDerived : AnInt { long long l; }; // sizeof(AnIntDerived) >= sizeof(AnInt) + sizeof(long long) // Assuming a typical 32- or 64-bit system, sizeof(AnIntDerived) == 16 (4 + padding + 8).
Om stoppning införs i ett objekt på grund av justeringskraven, kommer storleken att vara större än summan av storlekarna på elementen och basklasserna. Med
n
byte-inriktning är storlek typiskt den minsta multipeln avn
som är större än storleken på alla medlemmar och basklasser. VarjememN
kommer vanligtvis att placeras på en adress som är en multipel avalignof(memN)
, ochn
typiskt den störstaalignof
av alla medlemmarsalignof
. På grund av detta, om ett medlem med en mindrealignof
följs av ett medlem med en störrealignof
, finns det en möjlighet att det senare medlemmet inte kommer att justeras ordentligt om det placeras omedelbart efter det förstnämnda. I detta fall kommer stoppning (även känd som ett inriktningselement ) att placeras mellan de två delarna, så att det senare elementet kan ha sin önskade inriktning. Omvänt, om en medlem med en störrealignof
följs av en medlem med en mindrealignof
,alignof
ingen stoppning. Denna process kallas också "packning".
På grund av att klasser vanligtvis delar derasalignof
med den störstaalignof
, kommer klasser vanligtvis att anpassas tillalignof
av den största inbyggda typen som de direkt eller indirekt innehåller.// Assume sizeof(short) == 2, sizeof(int) == 4, and sizeof(long long) == 8. // Assume 4-byte alignment is specified to the compiler. struct Char { char c; }; // sizeof(Char) == 1 (sizeof(char)) struct Int { int i; }; // sizeof(Int) == 4 (sizeof(int)) struct CharInt { char c; int i; }; // sizeof(CharInt) == 8 (1 (char) + 3 (padding) + 4 (int)) struct ShortIntCharInt { short s; int i; char c; int j; }; // sizeof(ShortIntCharInt) == 16 (2 (short) + 2 (padding) + 4 (int) + 1 (char) + // 3 (padding) + 4 (int)) struct ShortIntCharCharInt { short s; int i; char c; char d; int j; }; // sizeof(ShortIntCharCharInt) == 16 (2 (short) + 2 (padding) + 4 (int) + 1 (char) + // 1 (char) + 2 (padding) + 4 (int)) struct ShortCharShortInt { short s; char c; short t; int i; }; // sizeof(ShortCharShortInt) == 12 (2 (short) + 1 (char) + 1 (padding) + 2 (short) + // 2 (padding) + 4 (int)) struct IntLLInt { int i; long long l; int j; }; // sizeof(IntLLInt) == 16 (4 (int) + 8 (long long) + 4 (int)) // If packing isn't explicitly specified, most compilers will pack this as // 8-byte alignment, such that: // sizeof(IntLLInt) == 24 (4 (int) + 4 (padding) + 8 (long long) + // 4 (int) + 4 (padding)) // Assume sizeof(bool) == 1, sizeof(ShortIntCharInt) == 16, and sizeof(IntLLInt) == 24. // Assume default alignment: alignof(ShortIntCharInt) == 4, alignof(IntLLInt) == 8. struct ShortChar3ArrShortInt { short s; char c3[3]; short t; int i; }; // ShortChar3ArrShortInt has 4-byte alignment: alignof(int) >= alignof(char) && // alignof(int) >= alignof(short) // sizeof(ShortChar3ArrShortInt) == 12 (2 (short) + 3 (char[3]) + 1 (padding) + // 2 (short) + 4 (int)) // Note that t is placed at alignment of 2, not 4. alignof(short) == 2. struct Large_1 { ShortIntCharInt sici; bool b; ShortIntCharInt tjdj; }; // Large_1 has 4-byte alignment. // alignof(ShortIntCharInt) == alignof(int) == 4 // alignof(b) == 1 // Therefore, alignof(Large_1) == 4. // sizeof(Large_1) == 36 (16 (ShortIntCharInt) + 1 (bool) + 3 (padding) + // 16 (ShortIntCharInt)) struct Large_2 { IntLLInt illi; float f; IntLLInt jmmj; }; // Large_2 has 8-byte alignment. // alignof(IntLLInt) == alignof(long long) == 8 // alignof(float) == 4 // Therefore, alignof(Large_2) == 8. // sizeof(Large_2) == 56 (24 (IntLLInt) + 4 (float) + 4 (padding) + 24 (IntLLInt))
Om strikt inriktning tvingas med
alignas
, kommer stoppning att användas för att tvinga typen att uppfylla den angivna inriktningen, även om den annars skulle vara mindre. Till exempel, med definitionen nedan, kommerChars<5>
att ha tre (eller eventuellt fler) stoppningsbyte infogade i slutet så att dess totala storlek är 8. Det är inte möjligt för en klass med en justering av 4 att ha en storlek av 5 eftersom det skulle vara omöjligt att göra en grupp av den klassen, så storleken måste "rundas upp" till ett multipel av 4 genom att sätta in vadderingsbyte.// This type shall always be aligned to a multiple of 4. Padding shall be inserted as // needed. // Chars<1>..Chars<4> are 4 bytes, Chars<5>..Chars<8> are 8 bytes, etc. template<size_t SZ> struct alignas(4) Chars { char arr[SZ]; }; static_assert(sizeof(Chars<1>) == sizeof(Chars<4>), "Alignment is strict.\n");
- Om två icke-statiska medlemmar i en klass har samma åtkomstspecifikation , kommer den som kommer senare i deklarationsordning garanteras att komma senare i objektrepresentationen. Men om två icke-statiska medlemmar har olika åtkomstspecifikationer, är deras relativa ordning inom objektet inte specificerad.
- Det är ospecificerat i vilken ordning basklassobjekt visas i ett objekt, om de förekommer i följd och om de visas före, efter eller mellan medlemsobjekt.
Aritmetiska typer
Smala karaktärstyper
Den unsigned char
typen använder alla bitar för att representera ett binärt tal. Därför, till exempel, om unsigned char
är 8 bitar lång, representerar de 256 möjliga bitmönstren för ett char
objekt de 256 olika värdena {0, 1, ..., 255}. Siffran 42 kommer garanterat att representeras av bitmönstret 00101010
.
Den signed char
typen har inga stoppningsbitar, dvs om signed char
är 8 bitar lång, har den 8 bitar kapacitet att representera ett nummer.
Observera att dessa garantier inte gäller andra typer än smala karaktärstyper.
Heltalstyper
De osignerade heltalstyperna använder ett rent binärt system, men kan innehålla stoppningsbitar. Till exempel är det möjligt (även om det är osannolikt) för unsigned int
att vara 64 bitar långa men bara kunna lagra heltal mellan 0 och 2 32 - 1 inklusive. De andra 32 bitarna skulle vara vadderingsbitar, som inte borde skrivas till direkt.
De signerade heltalstyperna använder ett binärt system med en teckenbit och eventuellt vadderingsbitar. Värden som tillhör det gemensamma intervallet för en signerad heltalstyp och motsvarande osignerad heltalstyp har samma representation. Till exempel, om bitmönstret 0001010010101011
av ett unsigned short
objekt representerar värdet 5291
, då det representerar även värdet 5291
, när tolkas som en short
objekt.
Det definieras av implementeringen om en två komplement, ens komplement eller teckenstorleksrepresentation används, eftersom alla tre system uppfyller kravet i föregående stycke.
Flytande punkttyper
Värdesrepresentationen av flytande punkttyper är implementeringsdefinerad. Vanligtvis överensstämmer float
och double
med IEEE 754 och är 32 och 64 bitar långa (så till exempel skulle float
ha 23 bitar med precision som skulle följa 8 exponentbitar och 1 teckenbit). Men standarden garanterar ingenting. Flytande punkttyper har ofta "trap-representationer", vilket orsakar fel när de används i beräkningar.
arrayer
En array-typ har ingen stoppning mellan dess element. Därför, en array med elementtypen T
är bara en sekvens av T
-objekt läggs ut i minnet, i ordning.
En flerdimensionell matris är en matris med matriser, och ovanstående gäller rekursivt. Om vi till exempel har deklarationen
int a[5][3];
då a
är en array av 5 uppsättningar av 3 int
s. Därför läggs a[0]
, som består av de tre elementen a[0][0]
, a[0][1]
, a[0][2]
, i minnet före a[1]
, som består av a[1][0]
, a[1][1]
och a[1][2]
. Detta kallas radordning för rad .