Men låt oss säga att en global variabel uppdateras i en funktion via en funktion pekare?
Kompilatorn har ingen aning om vilken funktion som uppdateras, hur vet den då att den inte kan optimera bort variablen.
int var = 0;
void main()
{
void (*func_ptr[3]) = {func1, func2, func3};
var = 0;
// Kompilatorn har ingen aning om att func kan ändra var
(*func_ptr[random(3)])();
if( var == 0)
{
printf("ERROR!!!!!\n");
}
}
void func1(void)
{
var = 0xCAFEBABE;
}
void func2(void)
{
var = 0xDEADBEEF;
}
void func3(void)
{
var = 0xBADBEEF;
}
Kompilatorn kan inte optimera bort "var" i den koden. Den symbolen blir ju extern och kan användas av andra objekt-filer som kommer åt den genom deklarationen:
Det vet den inte. Men den vet att du gör ett funktionsanrop och då kan vad som helst hända. Jag tror inte någon C-kompilator skulle våga optimera saker att ligga kvar i register medan den medvetet går in i en annan funktion. Inte kommer den att optimera bort globala variabler heller.
I just det här fallet skulle man med ett stycke rejäl analys kunna se vad som händer, men anta att funktionspekaren går ut ur aktuell källkodsfil. Då är det helt kört.
Skillnaden mot interrupt-fallet är alltså att där gör anropet utan att kompilatorn vet om när det sker. Nu valde du ju dessutom ganska enkla datatyper. Anta att du skrivit char[] eller struct nånting. Då hade ingen volatile i världen varit nog. Du hade behövt en semafor/mutex/valfri anna synkroniseringsmekanism.
superx skrev:Jag tror inte "rx_char" behöver vara volatile.
Det tror jag. Den används aldrig i main förutom en skrivning och det finns inga externa funktionsanrop. Det skulle inte förvåna mig om en optimerande kompilator väntar med skrivningen tills man antingen går ur loopen eller main. Som ju aldrig kommer hända eftersom det är en while(1) loop.
Dessutom i det här fallet kostar det ingen prestanda att variablen skrivs till varje iteration (det är ju det man vill), så det skadar ju inget att göra den volatile bara för att vara säker.
Vid funktionsanrop så är ju det "klassiska" att register pushas till stacken och popas vid retur.
Jag tror som sagt var inte att en global variabel någonsin optimeras som register, det här med volatile handlar ju (om variabeln inte är deklararerad som volatile) mer om att "om inget har skrivit till variabeln så kan den inte ha ändrats, så jag behöver inte kolla den igen, och eftersom jag inte behöver kolla den igen så vet jag att den här delen av koden inte behöver köras".
Typexemplet är ju det som är här, du deklararerar en variabel som FALSE och har sen en loop som kollar om den blivit TRUE. Men är den inte volatile så tycker kompilatorn "den här variabeln kan aldrig bli TRUE, alltså kan jag optimera bort hela koden som skulle körts om den blivit TRUE".