Vraag:
Wat is het verschil tussen het declareren van een variabele buiten de lus en het declareren van een statische binnenlus?
Cybergibbons
2014-03-01 16:00:29 UTC
view on stackexchange narkive permalink

Dit zijn twee manieren waarop ik een variabele buiten de lus (of welke functie dan ook) kan houden.

Ten eerste kan ik het declareren met een globaal bereik buiten de lus:

  void setup () {Serial.begin (9600);} int count = 0; void loop () {Serial.println (count); tel ++; delay (250);}  

Ik kan het ook statisch binnen de lus verklaren:

  void setup () {Serial.begin (9600);} void loop () {statische int count = 0; Serial.println (aantal); tel ++; delay (250);}  

Welk verschil zal dit maken?

Vier antwoorden:
#1
+10
asheeshr
2014-03-01 16:45:20 UTC
view on stackexchange narkive permalink

Het meest fundamentele verschil is het bereik.

In het eerste geval declareert u een globale variabele. Het is een variabele die na de definitie in elke scope toegankelijk is.

  void setup () {Serial.begin (9600);} void inc (); int count = 0; void loop ( ) {Serial.println (aantal); tel ++; inc (); delay (500);} void inc () // Kan de waarde van count {count = count + 1;};  

bewerken In het tweede geval declareert u een statische variabele met lokaal bereik. De variabele blijft gedurende de hele programma-run behouden, vergelijkbaar met globale variabelen, maar is alleen toegankelijk in het codeblok waarin het is gedeclareerd. Dit is hetzelfde voorbeeld, met slechts één wijziging. count is nu gedeclareerd als een statische variabele binnen loop.

  void inc (); void loop () {static int count = 0 ; Serial.println (aantal); tel ++; inc (); delay (500);}  

Dit zal niet compileren aangezien de functie inc () geen toegang heeft tot count .

Globale variabelen, hoe nuttig ze ook lijken, hebben enkele valkuilen. Deze kunnen zelfs schade aanrichten als het gaat om het schrijven van programma's die kunnen interageren met de fysieke omgeving. Dit is een heel eenvoudig voorbeeld van iets dat zeer waarschijnlijk zal gebeuren zodra programma's groter worden. Een functie kan onbedoeld de status van een globale variabele wijzigen.

  void setup () {Serial.begin (9600);} void another_function (); int state = 0; void loop () { // Blijf wisselen tussen de staat Serial.println (state); vertraging (250); state = state? 0: 1; // Sommige niet-gerelateerde functies roepen another_function ();} void another_function () {// Verandert onbedoeld state state = 1;}  

Dergelijke gevallen zijn erg moeilijk te debuggen. Dit type probleem kan echter gemakkelijk worden gedetecteerd door simpelweg een statische variabele te gebruiken.

  void setup () {Serial.begin (9600);} void another_function (); void loop () {statische int state = 0; // Blijf wisselen tussen de staat Serial.println (state);
vertraging (250); state = state? 0: 1; // Een niet-gerelateerde functie roept another_function ();} void another_function () {// Resulteert in een compilatietijdfout. Bespaart tijd. state = 1;}  
#2
+5
Philip Allgaier
2014-03-01 16:49:55 UTC
view on stackexchange narkive permalink

Functioneel gezien genereren beide versies hetzelfde resultaat, aangezien in beide gevallen de waarde van count wordt opgeslagen tussen de uitvoeringen van de loop () (ofwel omdat het is een globale variabele of omdat het is gemarkeerd als statisch en daarom zijn waarde behoudt).

Dus de beslissing om te kiezen komt neer op de volgende argumenten:

  • Over het algemeen wordt het in de informatica aangemoedigd om uw variabelen zo lokaal mogelijk te houden in termen van reikwijdte . Dit resulteert meestal in veel duidelijkere code met minder bijwerkingen en verkleint de kans dat iemand anders die globale variabele gebruikt je logica verknoeit). Bijv. in uw eerste voorbeeld kunnen andere logische gebieden de count -waarde wijzigen, terwijl in het tweede alleen die specifieke functie loop () dit kan doen).
  • Globale en statische variabelen nemen altijd het geheugen in beslag, terwijl de lokale bevolking dit alleen doet als ze binnen bereik zijn. In uw bovenstaande voorbeelden maakt dat geen verschil (aangezien u in de ene een globale, in de andere een statische variabele gebruikt), maar in grotere en complexere programma's kan en zou u geheugen kunnen besparen met niet-statische lokale gebruikers. Echter : als je een variabele in een logisch gebied hebt die heel vaak wordt uitgevoerd, overweeg dan om deze statisch of globaal te maken, omdat je anders een klein beetje aan prestatie verliest elke keer dat dat logicarea wordt ingevoerd, omdat het een beetje tijd om het geheugen voor die nieuwe variabele instantie toe te wijzen. U moet een balans vinden tussen geheugenbelasting en prestaties.
  • Andere punten, zoals een betere lay-out voor statische analyse of optimalisatie door de compiler, kunnen ook komen in het spel.
  • In sommige speciale scenario's kunnen er problemen zijn met de onvoorspelbare volgorde van initialisatie van statische elementen (niet zeker, vergelijk deze link echter).
  • Bron: vergelijkbare thread op arduino.cc

    Herintreding zou nooit een probleem moeten zijn op Arduino, omdat het geen gelijktijdigheid ondersteunt.
    Klopt. Dat was meer een algemeen punt, maar inderdaad niet relevant voor Arduino. Ik heb dat stukje verwijderd.
    Een statische variabele die binnen een bereik is gedeclareerd, zal altijd bestaan ​​en dezelfde ruimte gebruiken als een globale variabele! In de OP-code is het enige verschil welke code toegang heeft tot de variabele. In scipe static zal binnen hetzelfde bereik toegankelijk zijn.
    @jfpoilpret Dat is natuurlijk waar, en ik zie dat het betreffende deel in mijn antwoord een beetje misleidend was. Dat opgelost.
    #3
    +2
    JRobert
    2014-03-03 04:11:53 UTC
    view on stackexchange narkive permalink

    Beide variabelen zijn statisch - ze blijven gedurende de hele uitvoeringssessie bestaan. De globale is zichtbaar voor elke functie als deze de globale declareert - niet definieert, of als de functie de definitie volgt in dezelfde compilatie-eenheid (bestand + omvat).

    De definitie van count verplaatsen naar de binnenkant van een functie beperken beide het bereik van de zichtbaarheid tot de dichtstbijzijnde omsluitende set van {} es, en geven de functie-aanroepduur (het wordt gemaakt en vernietigd wanneer de functie wordt ingevoerd en verlaten). Door het ook statisch te geven, krijgt het de levensduur van de uitvoeringssessie, het bestaat van het begin tot het einde van de uitvoeringssessie, en blijft bestaan ​​bij functie-aanroepen.

    Tussen haakjes: wees voorzichtig met het gebruik van geïnitialiseerde statica binnen een functie, zoals ik heb gezien dat sommige versies van de GNU-compiler dit fout doen. Bij elke functie-invoer moet een automatische variabele met een initialisatieprogramma worden aangemaakt en geïnitialiseerd. Een statisch bestand met een initialisatieprogramma zou slechts één keer moeten worden geïnitialiseerd, tijdens de installatie van de uitvoering, voordat main () de controle krijgt (net zoals een globale zou zijn). Ik heb lokale statische gegevens opnieuw laten initialiseren bij elke functie-invoer alsof ze automaten waren, wat onjuist is. Test uw eigen compiler om zeker te zijn.

    Ik weet niet zeker of ik begrijp wat u bedoelt met een functie die een globaal declareert. Bedoel je als een `extern`?
    @PeterR.Bloomfield: Ik weet niet zeker over welk deel van mijn bericht je vraagt, maar ik verwees naar de twee voorbeelden van het OP - de eerste, een inherent globale definitie en de tweede, een lokale statische elektriciteit.
    #4
    -3
    Void Main
    2014-03-01 16:41:46 UTC
    view on stackexchange narkive permalink

    Volgens de documentatie van Atmel: "Als een globale variabele wordt gedeclareerd, zal een uniek adres in de SRAM aan deze variabele worden toegewezen op het moment van de programmalink."

    De volledige documentatie is hier (Tip # 2 voor globale variabelen): http://www.atmel.com/images/doc8453.pdf

    Zullen beide voorbeelden niet eindigen met een uniek adres in SRAM? Ze moeten allebei volharden.
    Ja, eigenlijk kun je die info vinden in hetzelfde document in tip # 6


    Deze Q&A is automatisch vertaald vanuit de Engelse taal.De originele inhoud is beschikbaar op stackexchange, waarvoor we bedanken voor de cc by-sa 3.0-licentie waaronder het wordt gedistribueerd.
    Loading...