Sida 1 av 1

Behövs volatile här?

Postat: 7 april 2015, 19:26:11
av arte
Hej,

Kod: Markera allt

volatile int etx_rcvd = FALSE; // Denna skall vara volatile

void main() 
{
    ... 
    while (!ext_rcvd) 
    {
        // Wait
    } 
    ...
}

interrupt void rx_isr(void) 
{
    ... 
    if (ETX == rx_char) 
    {
        etx_rcvd = TRUE;
    } 
    ...
}
I ovanstående kod så behvöer etx_rcvd vara volatile eftersom etx_rcvd kan ändras när som.

Men i nedanstående kod behövs volatile på rx_char? Borde vara samma sak?

Kod: Markera allt

int rx_char; // Behöver denna vara volatile? 

void main() 
{
    ... 
    while(1)
    {
        rx_char = i++;
        while (!ext_rcvd) 
        {
            // Wait
        } 
    }
    ...
}

interrupt void rx_isr(void) 
{
    ... 
    if (ETX == rx_char) 
    {
        etx_rcvd = TRUE;
    } 
    ...
}


Re: Behövs volatile här?

Postat: 7 april 2015, 19:33:24
av Icecap
Det är ganska enkelt: om en interrupt rutin ändrar/kan ändra en variabel som används i main-loop eller vice-versa ska man deklarera den som volatile.

Re: Behövs volatile här?

Postat: 7 april 2015, 19:55:04
av arte
Fast nu är det tvärtom. Variablen ändras i main loop och läses i interrupt rutinen.

I princip skulle rx_char kunna optimeras till ett register, då funkar inte koden.

Re: Behövs volatile här?

Postat: 7 april 2015, 19:57:57
av Icecap
"vice-versa" betyder "motsatt"

Re: Behövs volatile här?

Postat: 7 april 2015, 20:16:35
av arte
hehe tack...:)

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.

Kod: Markera allt

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;
}

Re: Behövs volatile här?

Postat: 7 april 2015, 21:56:02
av superx
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:

Kod: Markera allt

extern int var;
Jag tror inte "rx_char" behöver vara volatile.

Re: Behövs volatile här?

Postat: 7 april 2015, 22:00:25
av kodar-holger
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.

Re: Behövs volatile här?

Postat: 8 april 2015, 00:10:41
av Mr Andersson
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. :)

Re: Behövs volatile här?

Postat: 8 april 2015, 06:52:39
av superx
Ja, du har rätt! Det behövs nog faktiskt.

Re: Behövs volatile här?

Postat: 8 april 2015, 07:52:07
av Nerre
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".