Küsimus:
Mis vahe on muutuja deklareerimisel väljaspool tsüklit ja staatilisel deklareerimisel tsükli sees?
Cybergibbons
2014-03-01 16:00:29 UTC
view on stackexchange narkive permalink

Need on kaks viisi, kuidas saan muutujat hoida väljaspool tsüklit (või mis tahes funktsiooni).

Esiteks saan selle deklareerida globaalse ulatusega väljaspool tsüklit:

  void setup () {jada.algus (9600);} int arv = 0; void loop () {jada.println (loend); loend ++; delay (250);}  

Ma võin selle ka tsükli sees staatiliseks kuulutada:

  void setup () {Serial.begin (9600);} void loop () {staatiline int arv = 0; Serial.println (arv); loend ++; viivitus (250);}  

Mis vahet sellel on, kui üldse on?

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

Kõige põhilisem erinevus on ulatuses.

Esimesel juhul deklareerite globaalse muutuja. See on muutuja, millele pääseb pärast määratlust juurde igas ulatuses.

  void setup () {Serial.begin (9600);} void inc (); int count = 0; void loop ( ) {Seerial.println (arv); loend ++; inc (); delay (500);} void inc () // Saab redigeerida loenduse väärtust {count = count + 1;};  

Teisel juhul deklareerite staatilise muutuja kohalik ulatus. Muutuja püsib kogu programmi jooksul sarnaselt globaalsete muutujatega, kuid sellele pääseb juurde ainult selles koodiplokis, milles see deklareeritakse. See on sama näide, ainult ühe muudatusega. count deklareeritakse nüüd staatilise muutujana loop.

  void inc (); void loop () {staatiline int count = 0 ; Serial.println (arv); loend ++; inc (); delay (500);}  

Seda ei kompileerita, kuna funktsioonil inc () pole juurdepääsu koodile count .

Globaalsed muutujad, olgu need pealtnäha kasulikud, kaasnevad mõnega lõkse. Need võivad füüsilise ümbrusega suhtlemiseks mõeldud programmide kirjutamisel isegi kahjustada. See on väga lihtne näide millestki, mis juhtub üsna tõenäoliselt, niipea kui programmid hakkavad suuremaks minema. Funktsioon võib tahtmatult muuta globaalse muutuja olekut.

  void setup () {Serial.begin (9600);} void another_function (); int state = 0; void loop () { // Jätkake oleku Serial.println (osariik) vahetamist; viivitus (250); olek = olek? 0: 1; // Mõni mitteseotud funktsioon kutsub välja another_function ();} void another_function () {// Tahtmatult muudab oleku olekut = 1;}  

Selliseid juhtumeid on väga raske siluda. Seda tüüpi probleemi saab aga lihtsalt tuvastada, kasutades lihtsalt staatilist muutujat.

  void setup () {Serial.begin (9600);} void another_function (); tühine silmus () {staatiline int-olek = 0; // Jätkake oleku Serial.println (osariik) vahetamist;
viivitus (250); olek = olek? 0: 1; // Mõni mitteseotud funktsioon kutsub välja another_function ();} void another_function () {// Tulemuseks on kompileerimisviga. Säästab aega. olek = 1;}  
#2
+5
Philip Allgaier
2014-03-01 16:49:55 UTC
view on stackexchange narkive permalink

Funktsionaalsest vaatenurgast saadavad mõlemad versioonid sama tulemuse, kuna mõlemal juhul salvestatakse count väärtus loop () -i käivituste vahel (kas seetõttu, et see on globaalne muutuja või seetõttu, et see on tähistatud kui staatiline ja hoiab seetõttu oma väärtust).

Nii et valitud otsus tuleneb järgmistest argumentidest:

  • Üldiselt soovitatakse arvutiteaduses hoida oma muutujad ulatuse osas võimalikult kohalikud. See annab tavaliselt palju selgema koodi ja vähem kõrvalmõjusid ning vähendab tõenäosust, et keegi teine ​​kasutab seda globaalset muutujat teie loogikat keerates. Nt teie esimeses näites võivad muud loogikavaldkonnad muuta väärtust count , samas kui teises saab seda teha ainult see konkreetne funktsioon loop () ).
  • Globaalsed ja staatilised muutujad hõivavad alati mälu , kus seda teevad kohalikud ainult siis, kui need on reguleerimisala piires. Teie ülaltoodud näidetes pole vahet (kuna ühes kasutate globaalset, teises staatilist muutujat), kuid suuremates ja keerukamates programmides võib see nii olla ja võite salvestada mälu mittestaatiliste kohalike abil. Siiski : kui teie loogikavaldkonnas on muutuja, mida täidetakse väga sageli, kaaluge selle muutmist staatiliseks või globaalseks, sest muidu kaotate iga kord, kui loogikavälja sisestatakse, väikese jõudluse, kuna see võtab aega natuke aega mälu eraldamiseks selle uue muutuja eksemplari jaoks. Peate leidma tasakaalu mälukoormuse ja jõudluse vahel.
  • Samuti võivad tulla muud punktid, näiteks staatilise analüüsi parem paigutus või kompilaatori optimeerimine . mängu.
  • Mõnes erilises stsenaariumis võib staatiliste elementide ennustamatu initsialiseerimise järjekorras tekkida probleeme (pole selles punktis kindel, võrrelge seda linki).
  • Allikas: sarnane lõim saidil arduino.cc

    Uuesti sisenemine ei tohiks Arduinol kunagi probleem olla, kuna see ei toeta samaaegsust.
    Tõsi. See oli pigem üldine mõte, kuid ei olnud Arduino jaoks tõepoolest asjakohane. Eemaldasin selle jupi.
    Spektri sees deklareeritud staatiline muutuja on alati olemas ja kasutab sama ruumi kui globaalne muutuja! OP-koodis on ainus erinevus selles, milline kood muutujale juurde pääseb. Staatilisel kujul on staatiline juurdepääs samas ulatuses.
    @jfpoilpret See on muidugi tõsi ja ma näen, et vastav osa minu vastuses oli veidi eksitav. Parandas selle.
    #3
    +2
    JRobert
    2014-03-03 04:11:53 UTC
    view on stackexchange narkive permalink

    Mõlemad muutujad on staatilised - need püsivad kogu käivitusseansi vältel. Globaalne on nähtav igale funktsioonile, kui see deklareerib - ei defineeri - globaalset või kui funktsioon järgib sama kompileerimisüksuse (fail + sisaldab) määratlust.

    count definitsiooni teisaldamine funktsiooni sisemusse piirab nii nähtavuse ulatust lähima ümbritseva komplektiga {} es kui ka funktsiooni kutsumise eluea (see luuakse ja hävitatakse funktsiooni sisestamisel ja väljunud). Selle staatiliseks deklareerimine annab sellele ka seansi käivitamise kogu eluea, mis on olemas käivitamise seansi algusest lõpuni, püsides kogu funktsiooni väljakutses.

    BTW: olge initsialiseeritud staatika kasutamisel ettevaatlik funktsiooni sees, nagu olen näinud, et mõned gnu kompilaatori versioonid saavad seda valesti. Igal funktsioonikirjel tuleks luua ja lähtestada initsialiseerijaga automaatne muutuja. Staatilist koos initsialiseerijaga tuleks initsialiseerida ainult üks kord, käivitamise seadistamise ajal, enne kui main () saab juhtida (täpselt nagu globaalne oleks). Olen lasknud, et kohalik staatika taastatakse iga funktsiooni kirje kohta, nagu oleks see automaatika, mis on vale. Proovige oma kompilaator selles kindel olla.

    Ma pole kindel, et saan aru, mida mõtlete globaalseks kuulutava funktsiooni kohta. Kas peate silmas kui "välist"?
    -1
    #4
    -3
    Void Main
    2014-03-01 16:41:46 UTC
    view on stackexchange narkive permalink

    Atmeli dokumentatsiooni kohaselt: "Kui deklareeritakse globaalne muutuja, määratakse sellele muutujale programmi linkimise ajal SRAM-is ainulaadne aadress."

    Siin on täielik dokumentatsioon (vihje nr 2) globaalsete muutujate jaoks): http://www.atmel.com/images/doc8453.pdf

    Kas mõlemad näited ei saa SRAM-is ainulaadset aadressi? Mõlemad peavad püsima.
    Jah, selle teabe leiate samast dokumendist näpunäidest nr 6


    See küsimus ja vastus tõlgiti automaatselt inglise keelest.Algne sisu on saadaval stackexchange-is, mida täname cc by-sa 3.0-litsentsi eest, mille all seda levitatakse.
    Loading...