static
C kodu farklı yerlerde kullanılan kelimeyi gördüm ; (uygulama nesneler arasında paylaşılır) C # statik bir işlev / sınıf gibi mi?
static
C kodu farklı yerlerde kullanılan kelimeyi gördüm ; (uygulama nesneler arasında paylaşılır) C # statik bir işlev / sınıf gibi mi?
Yanıtlar:
(1) bir acemi iseniz daha yabancı bir konudur, işte bir örnek:
#include <stdio.h>
void foo()
{
int a = 10;
static int sa = 10;
a += 5;
sa += 5;
printf("a = %d, sa = %d\n", a, sa);
}
int main()
{
int i;
for (i = 0; i < 10; ++i)
foo();
}
Bu yazdırır:
a = 15, sa = 15
a = 15, sa = 20
a = 15, sa = 25
a = 15, sa = 30
a = 15, sa = 35
a = 15, sa = 40
a = 15, sa = 45
a = 15, sa = 50
a = 15, sa = 55
a = 15, sa = 60
Bu, bir işlevin çağrılar arasında bir durum tutması gerektiğinde ve genel değişkenleri kullanmak istemediğiniz durumlarda kullanışlıdır. Ancak, bu özellik çok az kullanılmalıdır - kodunuzu iş parçacığı açısından güvenli ve anlaşılmasını zorlaştırır.
(2) Yaygın olarak "erişim kontrolü" özelliği olarak kullanılır. Bazı işlevleri uygulayan bir .c dosyanız varsa, bu genellikle kullanıcılara yalnızca birkaç "genel" işlevi gösterir. Diğer işlevler static
, kullanıcının bunlara erişemeyeceği şekilde yapılmalıdır. Bu kapsülleme, iyi bir uygulama.
Wikipedia alıntısı :
C programlama dilinde, kapsamlarını içeren dosyaya ayarlamak için global değişkenler ve işlevlerle statik kullanılır. Yerel değişkenlerde statik, değişkeni otomatik olarak ayrılan bellek yerine statik olarak ayrılan bellekte saklamak için kullanılır. Dil, her iki bellek türünün uygulanmasını gerektirmezken, otomatik olarak ayrılan bellek normalde geçici bir çağrı yığını olarak uygulanırken, statik olarak ayrılan bellek genellikle programın veri bölümünde ayrılır.
Ve ikinci sorunuza cevap vermek için C # 'daki gibi değil.
Ancak C ++ ' static
da sınıf özniteliklerini (aynı sınıftaki tüm nesneler arasında paylaşılan) ve yöntemleri tanımlamak için de kullanılır. C'de sınıf yoktur, bu nedenle bu özellik önemsizdir.
.c
ve bir grup başlık dosyası olabilir, ancak şeytan her zaman tipik olmayan şeydedir.
Burada ele alınmayan bir kullanım daha vardır ve bu, bir işleve bağımsız değişken olarak dizi türü bildiriminin bir parçası olarak kullanılır:
int someFunction(char arg[static 10])
{
...
}
Bu bağlamda, bu işleve iletilen bağımsız değişkenlerin, char
içinde en az 10 öğe bulunan bir tür dizi olması gerektiğini belirtir . Daha fazla bilgi için soruma buradan bakın .
arg[0]
üzerine arg[9]
(aynı zamanda fonksiyon bir boş işaretçisi kabul etmez anlamına gelir) değerlerine sahip. Derleyiciler bu bilgileri bir şekilde optimizasyon için kullanabilirler ve statik analizörler bu bilgiyi, işleve hiçbir zaman boş bir işaretçi (ya da söyleyebiliyorsa belirtilenden daha az öğeye sahip bir dizi) verilmesini sağlamak için bu bilgileri kullanabilir.
static
C99'da verilen yeni aşırı yüklenmiş bir anlamdı . On yıldan fazla bir süredir, ancak tüm derleyici yazarları tüm C99 özelliklerini benimsemedi - bu yüzden C99 bir bütün olarak bilinmemektedir.
int arr[n];
, o zaman C99'da eklenen bir VLA (değişken uzunluklu dizi) . Demek istediğin bu muydu?
Kısa cevap ... duruma göre değişir.
Statik tanımlı yerel değişkenler, işlev çağrıları arasındaki değerlerini kaybetmez. Başka bir deyişle, bunlar küresel değişkenlerdir, ancak tanımlandıkları yerel işleve dahil edilirler.
Statik global değişkenler, tanımlandıkları C dosyasının dışında görünmez.
Statik işlevler, tanımlandıkları C dosyasının dışında görünmez.
private
C de yok , benzetmeniz iyi: statik belirli bir dosya için "özel" yapar. Ve C'deki dosyalar genellikle C ++ 'daki sınıflarla eşlenir.
Çok dosyalı değişken kapsam örneği
Burada statikin birden fazla dosyadaki fonksiyon tanımlarının kapsamını nasıl etkilediğini göstereceğim.
AC
#include <stdio.h>
/*
Undefined behavior: already defined in main.
Binutils 2.24 gives an error and refuses to link.
/programming/27667277/why-does-borland-compile-with-multiple-definitions-of-same-object-in-different-c
*/
/*int i = 0;*/
/* Works in GCC as an extension: https://stackoverflow.com/a/3692486/895245 */
/*int i;*/
/* OK: extern. Will use the one in main. */
extern int i;
/* OK: only visible to this file. */
static int si = 0;
void a() {
i++;
si++;
puts("a()");
printf("i = %d\n", i);
printf("si = %d\n", si);
puts("");
}
main.c
#include <stdio.h>
int i = 0;
static int si = 0;
void a();
void m() {
i++;
si++;
puts("m()");
printf("i = %d\n", i);
printf("si = %d\n", si);
puts("");
}
int main() {
m();
m();
a();
a();
return 0;
}
Derleyin ve çalıştırın:
gcc -c a.c -o a.o
gcc -c main.c -o main.o
gcc -o main main.o a.o
Çıktı:
m()
i = 1
si = 1
m()
i = 2
si = 2
a()
i = 3
si = 1
a()
i = 4
si = 2
yorumlama
si
her dosya için bir tane olmak üzere iki ayrı değişken vardıri
Her zamanki gibi, kapsam ne kadar küçük olursa, o kadar iyidir, bu yüzden her zaman değişkenleri static
bildirebilirsiniz.
C programlamasında, dosyalar genellikle "sınıfları" temsil etmek için kullanılır ve static
değişkenler sınıfın özel statik üyelerini temsil eder.
Standartlar bunun hakkında ne diyor
C99 N1256 taslak 6.7.1 "Depolama sınıfı belirteçleri" static
, bunun "depolama sınıfı belirleyicisi" olduğunu söylüyor .
6.2.2 / 3 "tanımlayıcıları Linkages" diyor static
ima internal linkage
:
Bir nesne veya işlev için dosya kapsamı tanımlayıcısının bildirimi, depolama sınıfı belirteci statik içeriyorsa, tanımlayıcı iç bağlantıya sahiptir.
ve 6.2.2 / 2 internal linkage
örneğimizdeki gibi davrandığını söylüyor :
Bir programın tamamını oluşturan çeviri birimleri ve kitaplıklar kümesinde, dış bağlantıya sahip belirli bir tanımlayıcının her bildirimi aynı nesneyi veya işlevi gösterir. Bir çeviri biriminde, iç bağlantıya sahip bir tanımlayıcının her bildirimi aynı nesneyi veya işlevi gösterir.
Burada "çeviri birimi, önişlemeden sonra bir kaynak dosyasıdır.
GCC bunu ELF (Linux) için nasıl uygular?
İle STB_LOCAL
bağlanması.
Derlersek:
int i = 0;
static int si = 0;
ve sembol tablosunu şunlarla sökün:
readelf -s main.o
çıktı şunları içerir:
Num: Value Size Type Bind Vis Ndx Name
5: 0000000000000004 4 OBJECT LOCAL DEFAULT 4 si
10: 0000000000000000 4 OBJECT GLOBAL DEFAULT 4 i
yani aralarındaki tek önemli fark bağlanmadır. Value
yalnızca .bss
bölüme kaydırıldıklarından farklı olmasını bekliyoruz.
STB_LOCAL
http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html adresindeki ELF spesifikasyonunda belgelenmiştir :
STB_LOCAL Yerel semboller, tanımlarını içeren nesne dosyasının dışında görünmez. Aynı ada sahip yerel semboller, birbirlerini etkilemeden birden fazla dosyada bulunabilir
temsil etmek için mükemmel bir seçimdir static
.
Statik olmayan değişkenler STB_GLOBAL
ve spesifikasyon şöyle diyor:
Bağlantı düzenleyicisi birkaç yeniden yerleştirilebilir nesne dosyasını birleştirdiğinde, aynı ada sahip birden çok STB_GLOBAL sembol tanımına izin vermez.
birden fazla statik olmayan tanımdaki bağlantı hataları ile uyumludur.
Optimizasyonu ile kranklarsak -O3
, si
sembol tamamen sembol tablosundan kaldırılır: yine de dışarıdan kullanılamaz. Neden optimizasyon olmadığında statik değişkenleri sembol tablosunda tutmalıyım? Herhangi bir şey için kullanılabilirler mi? Belki hata ayıklamak için.
Ayrıca bakınız
static
işlevler için benzer : https://stackoverflow.com/a/30319812/895245static
ile extern
: "karşıt" yok ki, nasıl kaynak dosyaları arasında pay değişkenlere extern kullanırım?C ++ anonim ad alanları
C ++ 'da, statik yerine anonim ad alanlarını kullanmak isteyebilirsiniz, bu da benzer bir etki yaratır, ancak tür tanımlarını daha da gizler: Adsız / anonim ad alanları ve statik işlevler
Değişir:
int foo()
{
static int x;
return ++x;
}
İşlev 1, 2, 3, vb. Döndürür --- değişken yığın üzerinde değildir.
static int foo()
{
}
Bu, bu işlevin yalnızca bu dosyada kapsamı olduğu anlamına gelir. Yani ac ve bc farklı s'lere sahip olabilir foo()
ve foo paylaşılan nesnelere maruz kalmaz. Bu yüzden ac'ta foo tanımladıysanız, ona b.c
başka bir yerden veya başka bir yerden erişemezdiniz .
Çoğu C kütüphanesinde tüm "özel" işlevler statiktir ve çoğu "genel" değildir.
İnsanlar C'deki 'statik' ifadesinin iki anlamı olduğunu söylüyorlar. Tek bir anlam veren alternatif bir görüntüleme yöntemi sunuyoruz:
İki anlamı olduğu için, C'de, 'statik' uygulanabilecek her öğenin zaten bu iki özellikten birine sahip olması, bu nedenle bu özel kullanım sadece diğerini içeriyor gibi görünüyor .
Örneğin, değişkenleri düşünün. İşlevlerin dışında bildirilen değişkenlerin zaten kalıcılığı vardır (veri segmentinde), bu nedenle 'statik' uygulamak yalnızca geçerli kapsamın (derleme birimi) dışında görünmemelerini sağlayabilir. Aksine, işlevler içinde bildirilen değişkenler zaten geçerli kapsam (işlev) dışında görünmezliğe sahiptir, bu nedenle 'statik' uygulamak yalnızca onları kalıcı hale getirebilir.
Fonksiyonlara 'statik' uygulamak, onu global değişkenlere uygulamak gibidir - kod mutlaka kalıcıdır (en azından dil içinde), bu nedenle yalnızca görünürlük değiştirilebilir.
NOT: Bu yorumlar yalnızca C için geçerlidir. C ++ 'da, sınıf yöntemlerine' statik 'uygulamak anahtar kelimeye gerçekten farklı bir anlam vermektedir. Benzer şekilde C99 dizi bağımsız değişkeni uzantısı için.
static
verir .
Wikipedia'dan:
C programlama dilinde, kapsamlarını içeren dosyaya ayarlamak için global değişkenler ve işlevlerle statik kullanılır. Yerel değişkenlerde statik, değişkeni otomatik olarak ayrılan bellek yerine statik olarak ayrılan bellekte saklamak için kullanılır. Dil, her iki bellek türünün uygulanmasını gerektirmezken, otomatik olarak ayrılan bellek normalde geçici bir çağrı yığını olarak uygulanırken, statik olarak ayrılan bellek genellikle programın veri bölümünde ayrılır.
static
farklı bağlamlarda farklı şeyler ifade eder.
C işlevinde statik bir değişken bildirebilirsiniz. Bu değişken yalnızca işlevde görülebilir, ancak yalnızca bir kez başlatıldığı ve değerini koruduğu için bir global gibi davranır. Bu örnekte, her aradığınızda foo()
artan bir sayı yazdırılır. Statik değişken yalnızca bir kez başlatılır.
void foo ()
{
static int i = 0;
printf("%d", i); i++
}
Statik bir başka kullanım, bir .c dosyasına bir işlev veya genel değişken uyguladığınız ancak sembolünün .obj
dosya tarafından oluşturulanın dışında görünmesini istemediğiniz durumdur . Örneğin
static void foo() { ... }
Bir değişkeni statik işlevde bildirirseniz, değeri işlev çağrısı yığınında depolanmaz ve işlevi yeniden çağırdığınızda kullanılabilir olmaya devam eder.
Genel bir değişken statik bildirirseniz, kapsamı bildirdiğiniz dosya içinde kısıtlanır. Bu, tüm programınız boyunca okunabilen ve değiştirilebilen normal bir küreselden biraz daha güvenlidir.
Eski bir soruyu cevaplamaktan nefret ediyorum, ancak hiç kimsenin K&R'nin "C Programlama Dili" nin A4.1 bölümünde nasıl açıkladığını söylemediğini sanmıyorum.
Kısacası, statik kelimesi iki anlamla kullanılır :
static
anahtar kelime (kodda anahtar kelime olarak kullanılmasına büyük önem verilir) bir bildirimle kullanıldığında, nesnenin iç bağlantısını verir, böylece yalnızca o çeviri biriminde kullanılabilir. Ancak anahtar kelime bir işlevde kullanılırsa, nesnenin depolama sınıfını değiştirir (nesne yine de bu işlev içinde görünür olur). Statikin tersi, extern
bir nesneye harici bağlantı sağlayan anahtar kelimedir.Peter Van Der Linden "Uzman C Programlama" da şu iki anlamı vermektedir:
register
bir depolama sınıfı belirleyicisi (C99 6.7.1 Depolama sınıfı belirleyicileri) yaptığı için görüşünüze katılmıyor . Ve bu sadece bir ipucundan daha fazlasıdır, örneğin derleyicinin bir kayıt ayırıp ayırmamasına bakılmaksızın operatör adresini &
depolama sınıfına sahip bir nesneye uygulayamazsınız register
.
C dilinde, statik, kullanım kapsamına bağlı olarak iki anlama sahiptir. Genel kapsamda, bir nesne dosya düzeyinde bildirildiğinde, o nesnenin yalnızca o dosya içinde görünür olduğu anlamına gelir.
Başka bir kapsamda, belirli bir kapsamın girildiği farklı zamanlar arasında değerini koruyacak bir nesne bildirir. Örneğin, bir prosedür içinde int çıkarılırsa:
void procedure(void)
{
static int i = 0;
i++;
}
'i' değeri yordama yapılan ilk çağrıda sıfıra başlatılır ve değer, yordam her çağrıldığında korunur. 'i' basılmışsa, 0, 1, 2, 3, ...
Fonksiyonlardaki statik değişkenlerin, o fonksiyonun ilk girişinde başlatıldığını ve çağrıları bittikten sonra bile devam ettiğini not etmek önemlidir; özyinelemeli işlevlerde statik değişken yalnızca bir kez başlatılır ve tüm özyinelemeli çağrılarda ve hatta işlev çağrısı bittikten sonra da devam eder.
Değişken bir fonksiyonun dışında oluşturulmuşsa, programcının sadece değişkeni bildirdiği kaynak dosyada değişkeni kullanabileceği anlamına gelir.
Bunu bir mytest.c
dosyada bildirirseniz :
static int my_variable;
Sonra bu değişken sadece bu dosyadan görülebilir. Değişken başka bir yere aktarılamaz.
Bir işlevin içinde bildirirseniz, değişken her işlev çağrıldığında değerini korur.
Statik bir işlev dosyanın dışından dışa aktarılamaz. Yani bir *.c
dosyada, fonksiyonları ve değişkenleri statik olarak bildirirseniz gizlersiniz.
C'deki statik değişkenler programın ömrüne sahiptir.
Bir işlevde tanımlanırlarsa, yerel kapsamları vardır, yani yalnızca bu işlevlerin içinden erişilebilirler. Statik değişkenlerin değeri, fonksiyon çağrıları arasında korunur.
Örneğin:
void function()
{
static int var = 1;
var++;
printf("%d", var);
}
int main()
{
function(); // Call 1
function(); // Call 2
}
Yukarıdaki programda, var
veri segmentinde saklanır. Kullanım ömrü tüm C programıdır.
İşlev çağrısı 1'den var
sonra 2 var
olur. İşlev çağrısı 2'den sonra 3 olur.
var
İşlev çağrıları arasında değeri yok edilmez.
Eğer var
sigara statik ve yerel değişkeni arasındaki vardı, C programında yığın segmentinde saklanır. İşlev döndükten sonra işlevin yığın çerçevesi yok edildiğinden, değeri var
de yok edilir.
Başlatılan statik değişkenler C programının veri segmentinde, başlatılmamış olan değişkenler BSS segmentinde saklanır.
Statik hakkında başka bir bilgi: Değişken genel ve statik ise, C programının yaşam süresi vardır, ancak dosya kapsamı vardır. Yalnızca bu dosyada görünür.
Bunu denemek için:
static int x;
int main()
{
printf("Accessing in same file%d", x):
}
extern int x;
func()
{
printf("accessing in different file %d",x); // Not allowed, x has the file scope of file1.c
}
run gcc -c file1.c
gcc -c file2.c
Şimdi bunları kullanarak bağlanmaya çalışın:
gcc -o output file1.o file2.o
X, dosya1.c dosya kapsamına sahip olduğundan ve bağlayıcı, file2.c dosyasında kullanılan x değişkenine yapılan başvuruyu çözümleyemeyeceği için bir bağlayıcı hatası verir.
Referanslar:
static int var = 1;
değeri her seferinde bire geri değiştirmiyor
Statik değişken, bir işlevde kullanabileceğiniz özel bir değişkendir ve verileri aramalar arasında kaydeder ve aramalar arasında silmez. Örneğin:
void func(){
static int count; // If you don't declare its value, the value automatically initializes to zero
printf("%d, ", count);
++count;
}
void main(){
while(true){
func();
}
}
Çıktı:
0, 1, 2, 3, 4, 5, ...
printf("%d, ", count); count++;
printf ( "% d", sayım ++) (: P mühim değil) `ile.
2 vaka var:
(1) static
Belirtilen yerel değişkenler : Yığın yerine veri segmentine ayrılmıştır. İşlevi tekrar çağırdığınızda değeri korunur.
(2) Genel değişkenler veya beyan edilen fonksiyonlar static
: Derleme ünitesi dışında görünmez (örn. Bağlantı sırasında sembol tablosundaki yerel sembollerdir).
Statik değişkenler kendi kapsamları dışında olduklarında bile değerlerini koruma özelliğine sahiptirler , dolayısıyla statik değişkenler önceki değerlerinde önceki değerlerini korurlar ve yeni kapsamda yeniden başlatılmazlar.
Örneğin buna bakın - Program çalışırken statik bir int değişkeni bellekte kalır. Değişkenin bildirildiği bir işlev çağrısı bittiğinde normal veya otomatik değişken yok edilir.
#include<stdio.h>
int fun()
{
static int count = 0;
count++;
return count;
}
int main()
{
printf("%d ", fun());
printf("%d ", fun());
return 0;
}
Bu çıktı: 1 2
Statik olarak bildirildiği için 1 bellekte kaldığı için
Statik değişkenler (global değişkenler gibi), açıkça başlatılmazsa 0 olarak başlatılır. Örneğin, aşağıdaki programda, x değeri 0 olarak yazdırılırken, y değeri çöptür. Daha fazla ayrıntı için buna bakın.
#include <stdio.h>
int main()
{
static int x;
int y;
printf("%d \n %d", x, y);
}
Bu çıktı: 0 [some_garbage_value]
Bunlar, bir acemi için yukarıda açıklanmayan bulduğum en önemli olanlar!
C programlamasında, static
görünürlüğü olduğu kadar yaşam süresini de kontrol eden ayrılmış bir anahtar kelimedir. Bir değişkeni bir işlev içinde statik olarak bildirirsek, yalnızca bu işlev boyunca görünür olur. Bu kullanımda, bu statik değişkenin ömrü bir işlev çağrıldığında başlar ve bu işlevin yürütülmesinden sonra yok olur. aşağıdaki örneği görebilirsiniz:
#include<stdio.h>
int counterFunction()
{
static int count = 0;
count++;
return count;
}
int main()
{
printf("First Counter Output = %d\n", counterFunction());
printf("Second Counter Output = %d ", counterFunction());
return 0;
}
Yukarıdaki program bize bu Çıktıyı verecektir:
First Counter Output = 1
Second Counter Output = 1
Çünkü fonksiyonu çağırır çağırmaz başlayacaktır count = 0
. Ve biz yürütürken counterFunction
sayım değişkenini yok edecektir.