De Avr-libc-faq heeft het fout.
IN "a=b=c=val;" staat er niet "c=val; b=c; a=b;", maar "a= (b= (c=val));". En in de C-standaard staat dat een assignment die gebruikt wordt waar een waarde verwacht wordt de ge-assignde waarde teruggeeft.
In de praktijk:
volatile int a, b, c;
void testit (int val)
{
a=b=c=val;
}
Met "volatile" geef ik aan dat de variabele zonder waarschuwing tussendoor veranderd kan worden. Dit is ook de manier waarop hardware registers gedefinieerd zijn.
zou anders iets worden als: laad PINB in een register, herhaal: test bit 1 in het register of dat al 1 geworden is. Met volatile vertel je de compiler dat ie steeds PINB weer op moet halen alvorens dat ie de test gaat doen.
Met de avr compiler wordt dat:
testit:
sts c+1,r25
sts c,r24
sts b+1,r25
sts b,r24
sts a+1,r25
sts a,r24
ret
De functie parameter in R24/R25 wordt eerst in c, dan in b en dan in a gezet.
De arm-compiler doet:
testit:
ldr r1, .L3
ldr r2, .L3+4
ldr r3, .L3+8
str r0, [r1]
str r0, [r2]
str r0, [r3]
bx lr
Hierbij optimaliseert ie ook nog r1 en r2 weg als ik "static" voor de abc declaratie zet. (*) Merk op dat elders c op het laagste adres wordt gezet, dus weer is het eerst c, dan b, dan a.
En als laatste bij x86 wordt het:
testit:
movl %edi, c(%rip)
movl %edi, b(%rip)
movl %edi, a(%rip)
ret
met de functie parameter in %edi en gewoon een enkele instructie om de store-naar-memory te regelen.
(*) Dat had ik eerst gedaan, en omdat er in m'n source niets anders bevat was ik bang dat ie misschien toch aannames ging doen van: omdat deze variabelen buiten deze source niet bekend mogen zijn, en ik in deze source kan zien dat ze niet gewijzigd worden, weet ik zeker dat er tussendoor geen wijzigingen zijn. Dat is een foute gedachte van me: die a-b-c variabelen hadden zomaar een hardware register kunnen zijn wat door de hardware veranderd wordt. Ook als er in deze source geen code is die ze verandert!