Döngü dışında bir değişken bildirmek ile statik iç döngü bildirmek arasındaki fark nedir?


9

Bunlar döngü (veya herhangi bir işlev) dışında bir değişkeni tutabileceğiniz iki yoludur.

İlk olarak, döngü dışında küresel kapsam ile ilan edebilirim:

void setup()
{
    Serial.begin(9600);
}

int count = 0;

void loop()
{
    Serial.println(count);
    count++;

    delay(250);
}

Ayrıca döngü içinde statik ilan edebilir:

void setup()
{
    Serial.begin(9600);
}

void loop()
{
    static int count = 0;

    Serial.println(count);
    count++;

    delay(250);
}

Varsa, ne fark eder?

Yanıtlar:


10

En temel fark kapsamdır.

İlk durumda, global bir değişken bildiriyorsunuz. Tanımından sonra her kapsamda erişilebilen bir değişkendir.

void setup()
{
    Serial.begin(9600);
}

void inc();
int count = 0;

void loop()
{
    Serial.println(count);
    count++;

    inc();

    delay(500);
}

void inc() //Can edit the value of count
{
  count=count+1;
};

İkinci durumda, yerel kapsamı olan bir statik değişken bildiriyorsunuz. Değişken, global değişkenlere benzer tüm program çalışması için devam eder, ancak yalnızca bildirildiği kod bloğundan erişilebilir. Bu, yalnızca bir değişiklikle aynı örnektir. countartık içeride statik bir değişken olarak bildirildi loop.

void inc();

void loop()
{
    static int count = 0;
    Serial.println(count);
    count++;

    inc();

    delay(500);
}

Bu, işlevin inc()erişimi olmadığından derlenmez count.

Her ne kadar faydalı gibi görünse de, küresel değişkenler bazı zorluklarla birlikte gelir. Fiziksel çevreyle etkileşime girebilecek programlar yazmak söz konusu olduğunda bunlar bile hasara neden olabilir. Bu, programlar büyümeye başlar başlamaz, gerçekleşmesi muhtemel bir şeyin çok temel bir örneğidir. Bir işlev yanlışlıkla global bir değişkenin durumunu değiştirebilir.

void setup()
{
    Serial.begin(9600);
}
void another_function();
int state=0;

void loop()
{
    //Keep toggling the state
    Serial.println(state);
    delay(250);
    state=state?0:1;

    //Some unrelated function call
    another_function();
}

void another_function()
{
  //Inadvertently changes state
  state=1;

}

Bu tür vakaların hatalarını ayıklamak çok zordur. Ancak bu tür bir problem, sadece statik bir değişken kullanılarak kolayca tespit edilebilir.

void setup()
{
    Serial.begin(9600);
}
void another_function();

void loop()
{
    static int state=0;

    //Keep toggling the state
    Serial.println(state);
    delay(250);
    state=state?0:1;

    //Some unrelated function call
    another_function();
}

void another_function()
{
  //Results in a compile time error. Saves time.
  state=1;

}

5

İşlevsel bir perspektiften, her iki sürüm de aynı sonucu üretir, çünkü her iki durumda da değeri count, loop()(genel bir değişken olduğu için veya staticdeğeri olarak işaretlendiği ve bu nedenle değerini koruduğu için) yürütmeleri arasında saklanır .

Bu nedenle, hangi kararın seçileceği aşağıdaki argümanlara iner:

  1. Genel olarak bilgisayar bilimlerinde değişkenlerinizin kapsam açısından mümkün olduğunca yerel tutulması teşvik edilir . Bu genellikle daha az yan etki ile çok daha net bir kodla sonuçlanır ve mantığınızı bozan bu küresel değişkeni kullanan birisinin şansını azaltır). Örneğin ilk örneğinizde, diğer mantık alanları countdeğeri değiştirebilirken , ikincisinde yalnızca belirli bir işlev loop()bunu yapabilir).
  2. Global ve statik değişkenler her zaman hafızayı işgal eder , burada yerliler sadece kapsamdayken yapar. Farketmeyen yukarıdaki örneklerinizde (birinde küresel, diğerinde statik değişken kullandığınızdan), ancak daha büyük ve daha karmaşık programlarda statik olmayan yerel ayarları kullanarak bellek tasarrufu yapabilirsiniz. Ancak : Çok sık yürütülen bir mantık alanında bir değişkeniniz varsa, bunu statik veya global yapmayı düşünün, aksi takdirde o mantık alanına her girdiğinde küçük bir performans kaybedersiniz, çünkü bu işlem biraz zaman alır. o yeni değişken örneği için bellek ayırın. Bellek yükü ile performans arasında bir denge bulmanız gerekir.
  3. Statik analiz için daha iyi düzen veya derleyici tarafından optimizasyon gibi diğer noktalar da devreye girebilir.
  4. Bazı özel senaryolarda, statik öğelerin öngörülemeyen başlatma sırası ile ilgili sorunlar olabilir (bu noktadan emin değilsiniz, bu bağlantıyı karşılaştırın ).

Kaynak: arduino.cc üzerinde benzer konu


Eşzamanlılığı desteklemediğinden, yeniden giriş asla Arduino'da bir sorun olmamalıdır.
Peter Bloomfield

Doğru. Bu daha genel bir noktaydı, ama gerçekten Arduino için geçerli değildi. O parçayı çıkardım.
Philip Allgaier

1
Bir kapsam içinde bildirilen statik bir değişken her zaman var olur ve global değişkenle aynı alanı kullanır! OP kodunda tek fark, hangi kodun değişkene erişebileceğidir. Scipe statik olarak aynı kapsamda erişilebilir olacaktır.
jfpoilpret

1
@jfpoilpret Bu elbette doğrudur ve cevabımdaki ilgili kısmın biraz yanıltıcı olduğunu görüyorum. Bunu düzelttim.
Philip Allgaier

2

Her iki değişken de statiktir - tüm yürütme oturumu için devam ederler. Global, global tanımladığında - tanımlamıyorsa veya işlev aynı derleme birimindeki (dosya + içerir) tanımı izliyorsa, herhangi bir işlev tarafından görülebilir.

countBir işlevin tanımını taşımak, görünürlük kapsamını en yakın ekli {}es kümesiyle sınırlar ve işlev çağırma ömrü verir (işlev girilip çıkıldığında oluşturulur ve yok edilir). O bildirmek statichem de işlev çağrıları boyunca devam eden, uygulama oturumu başlangıcından sonuna kadar mevcut yürütmeyi oturum kullanım sağlar.

BTW: gnu derleyicisinin bazı sürümlerinin bunu yanlış yaptığını gördüğüm için, bir işlev içinde başlatılmış statik kullanma konusunda dikkatli olun. Her fonksiyon girişinde başlatıcı içeren bir otomatik değişken oluşturulmalı ve başlatılmalıdır. Başlatıcısı olan bir statik, yürütme kurulumu sırasında, main () kontrolüne (genel olarak olduğu gibi) verilmeden önce yalnızca bir kez başlatılmalıdır. Ben her biri otomatik olarak sanki, her işlev girişinde yeniden başlatılmış yerel statik aldık, bu da yanlış. Emin olmak için kendi derleyicinizi test edin.


Global olarak bildiren bir işlev hakkında ne demek istediğinizi anladığımdan emin değilim. Şunu mu demek istediniz extern?
Peter Bloomfield

@ PeterR.Bloomfield: Yazımın hangi kısmını sorduğunuzdan emin değilim, ama OP'nin iki örneğinden bahsediyordum - birincisi, doğası gereği küresel bir tanım ve ikincisi, yerel bir statik.
JRobert

-3

Atmel'in belgelerine göre: "Bir global değişken bildirilirse, program bağlantı zamanında bu değişkene SRAM'de benzersiz bir adres atanacaktır."

Dokümanın tamamı burada (Global değişkenler için 2. ipucu): http://www.atmel.com/images/doc8453.pdf


4
Her iki örnek de SRAM'de benzersiz bir adresle sonuçlanmayacak mı? İkisinin de devam etmesi gerekiyor.
Cybergibbons

2
Evet aslında bu bilgiyi aynı belgedeki ipucu # 6'da bulabilirsiniz
jfpoilpret
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.