En annan intressant effekt har med "alignment" att göra.
Ta t.ex detta lilla exempel:
Kod: Markera allt
struct stru {
unsigned char x;
unsigned long y;
};
struct stru s;
unsigned long i;
void main()
{
for (i=0; i<100; i++)
{
s.x = i;
s.y = i;
}
}
En struct med en "char" och en "long".
Default vid kompileringen sätta det in 3 st "dummy bytes" efter char'en så att
long'en ska komma på en jämn "long-adress". Processorn accessar alltid minnet
i 32 eller 64-bitars bitar, och om en variabel inte ligger på en jämn adress så
blir det lite pussel av det hela.
Om vi kompilerar med default (d.v.s med "member_align"):
Kod: Markera allt
$ cc /list /machin_code /nooptimize stru
$ link /map /full stru
så får vi en kod som ser ut så här (d.v.s för de två tilldelningarna inne i loopen, rad 13 och 14):
Kod: Markera allt
...
1 11 for (i=0; i<100; i++)
2 12 {
2 13 s.x = i;
2 14 s.y = i;
1 15 }
...
A41D0020 00E4 LDQ R0, 32(FP) ; 000013
A0000000 00E8 LDL R0, I ; R0, (R0)
A43D0018 00EC LDQ R1, 24(FP)
A2010000 00F0 LDL R16, S ; R16, (R1)
4A003610 00F4 ZAP R16, 1, R16
441FF000 00F8 AND R0, 255, R0
46000410 00FC BIS R16, R0, R16
B2010000 0100 STL R16, S ; R16, (R1)
A63D0020 0104 LDQ R17, 32(FP) ; 000014
A2310000 0108 LDL R17, I ; R17, (R17)
A65D0018 010C LDQ R18, 24(FP)
B2320004 0110 STL R17, 4(R18)
Alltså 8 instruktioner för "s.x = i;" och 4 för "s.y = i;"
Ganska förväntat, en long är effektivare än en char.
Vi ser också (i MAP filen att structen tar *8* bytes utrymme eftersom kompilatorn
har tryckt in 3 "dummy-bytes" mellan x och y.
Om vi däremot kompilerar utan "member_align" så blir det (ungefär) samma kod för
tilldelningen av char'en, men för long'en (som nu ligger över två minnes platser) så
blir det en stor skillnad. Istället för *4* instruktioner så blir det:
Kod: Markera allt
$ cc /list /machin_code /nooptimize /nomember_align stru.c
$ link /map /full stru
Kod: Markera allt
A65D0020 0104 LDQ R18, 32(FP) ; 000014
A2520000 0108 LDL R18, I ; R18, (R18)
A41D0018 010C LDQ R0, 24(FP)
20000001 0110 LDA R0, 1(R0)
2E000003 0114 LDQ_U R16, 3(R0)
2C200000 0118 LDQ_U R1, (R0)
4A400CF3 011C INSLH R18, R0, R19
4A400571 0120 INSLL R18, R0, R17
4A000C50 0124 MSKLH R16, R0, R16
48200441 0128 MSKLL R1, R0, R1
46130410 012C BIS R16, R19, R16
44310401 0130 BIS R1, R17, R1
3E000003 0134 STQ_U R16, 3(R0)
3C200000 0138 STQ_U R1, (R0)
Den gör dubbla minnes accesser och pusslar ihop det hela till en long.
Structen s tar nu dock bara 5 bytes eftersom ingen alignment har gjorts.
Från 4 instruktioner till 14.
I de flesta fall kan man låta kompilatorn fylla ut där den vill, men om man har
fasta format som man hanterar med struct's och union's, så är det inte alltid
man kan göra det. D.v.s om lagringsformatet på en struktur redan är given.
Allra bäst är att köra med default optimize, då försvinner loopen helt och ersätts
med två enkla tilldelningar av 99 till x och y...
