Variabel statis di dalam fungsi di C

119

Apa yang akan dicetak? 6 6 atau 6 7? Dan mengapa?

void foo()
{
    static int x = 5;
    x++;
    printf("%d", x);
}

int main()
{
    foo();
    foo();
    return 0;
}
Vadiklk
sumber
54
Apa masalahnya untuk dicoba?
Andrew
12
Apakah Anda mencoba mengetik ini dan melihat sendiri?
wilhelmtell
21
Saya ingin mengerti mengapa.
Vadiklk
7
@Vadiklk jadi ajukan pertanyaan dimulai dengan "Mengapa"
Andrey
1
ideone.com/t9Bbe Apa yang Anda harapkan? Apakah hasilnya tidak sesuai dengan ekspektasi Anda? Mengapa Anda mengharapkan hasil Anda?
eckes

Jawaban:

187

Ada dua masalah di sini, masa hidup dan ruang lingkup.

Ruang lingkup variabel adalah tempat nama variabel dapat dilihat. Di sini, x hanya terlihat di dalam fungsi foo ().

Umur variabel adalah periode keberadaannya. Jika x didefinisikan tanpa kata kunci statis, masa hidup akan dimulai dari entri ke foo () hingga kembalian dari foo (); sehingga akan diinisialisasi ulang menjadi 5 pada setiap panggilan.

Kata kunci statis bertindak untuk memperpanjang umur variabel ke masa program; misalnya inisialisasi terjadi sekali dan hanya sekali dan kemudian variabel mempertahankan nilainya - apa pun yang terjadi - pada semua panggilan mendatang ke foo ().


sumber
15
@ devanl, ya kami.
orion elenzil
1
Sederhana dan logis :)
Dimitar Vukman
dalam skenario apa kita perlu mendeklarasikan variabel sebagai statis di dalam fungsi ?, hanya ingin tahu karena saya belum pernah menggunakan ini sebelumnya?
Akay
saya akan mengucapkan terima kasih, tetapi ini semua dijawab di bagian paling atas halaman. itu membuat saya tertawa bahwa orang tidak hanya menjalankan kode mereka sendiri. xD
Genangan
Jawaban ini salah. Saat Anda memikirkan tentang fungsi rekursif, definisi seperti yang dijelaskan di sini tidak menjelaskan perilakunya!
Philip Couling
53

Hasil : 6 7

Alasan : variabel statis hanya dijalankan sekali (tidak seperti variabel otomatis) dan definisi lebih lanjut dari variabel statis akan dilewati selama waktu proses. Dan jika tidak dijalankan secara manual, ini diinisialisasi dengan nilai 0 secara otomatis. Begitu,

void foo() {
    static int x = 5; // assigns value of 5 only once
    x++;
    printf("%d", x);
}

int main() {
    foo(); // x = 6
    foo(); // x = 7
    return 0;
}
Nitesh Borad
sumber
10

6 7

compiler mengatur bahwa inisialisasi variabel statis tidak terjadi setiap kali fungsi dimasukkan

Chaim Geretz
sumber
10

Itu sama dengan memiliki program berikut:

static int x = 5;

void foo()
{
    x++;
    printf("%d", x);
}

int main()
{
     foo();
     foo();
     return 0;
}

Semua yang dilakukan kata kunci statis dalam program itu adalah ia memberi tahu kompiler (pada dasarnya) 'hei, saya memiliki variabel di sini yang saya tidak ingin orang lain mengaksesnya, jangan beri tahu orang lain bahwa itu ada'.

Di dalam metode, kata kunci statis memberi tahu kompiler hal yang sama seperti di atas, tetapi juga, 'jangan beri tahu siapa pun bahwa ini ada di luar fungsi ini, seharusnya hanya dapat diakses di dalam fungsi ini'.

saya harap ini membantu

Richard J. Ross III
sumber
13
Sebenarnya tidak sama. Masih ada masalah scope pada X. Dalam contoh ini, Anda bisa menyodok dan futz dengan xmain; itu global. Dalam contoh aslinya xadalah lokal ke foo, hanya terlihat saat berada di dalam blok itu, yang umumnya lebih disukai: jika foo ada untuk dipelihara xdengan cara yang dapat diprediksi dan terlihat, maka membiarkan orang lain menyodoknya umumnya berbahaya. Sebagai manfaat lain dari menjaganya dalam ruang lingkup, foo() itu juga tetap foo()portabel.
pengguna2149140
2
@ user2149140 'jangan beri tahu siapa pun bahwa ini ada di luar fungsi ini, seharusnya hanya dapat diakses di dalam fungsi ini'
DCShannon
3
Meskipun Anda telah membahas masalah cakupan karena tempat variabel dideklarasikan, deskripsi statis sebagai memengaruhi cakupan, bukan seumur hidup, tampaknya salah.
DCShannon
1
@Chameleon Pertanyaannya ditandai sebagai c, jadi dalam konteks ini, contoh Anda akan ilegal di lingkup global. (C membutuhkan penginisialisasi konstan untuk global, C ++ tidak).
Richard J. Ross III
5

Variabel statis di dalam fungsi memiliki umur selama program Anda berjalan. Itu tidak akan dialokasikan setiap kali fungsi Anda dipanggil dan dibatalkan alokasinya saat fungsi Anda kembali.

Donotalo
sumber
Mengatakan ini seperti variabel "global" dan kemudian mengatakan KECUALI Anda tidak dapat mengaksesnya adalah sebuah oxymoron. Global artinya dapat diakses di mana saja. Yang mana dalam hal ini fungsi DI DALAM statis TIDAK dapat diakses di mana-mana. Masalah dalam OP seperti yang dicatat orang lain adalah tentang ruang lingkup dan masa pakai. Mohon jangan bingung orang-orang menggunakan istilah 'global' dan menyesatkan mereka dalam lingkup variabel.
ChuckB
@ChuckB: Benar. Diperbaiki. Ya sudah 6 tahun. Jawaban saya sebelumnya memiliki persepsi 6 tahun yang lalu!
Donotalo
5

Hasil: 6,7

Alasan

Deklarasi xada di dalam footetapi x=5inisialisasi terjadi di luar foo!

Yang perlu kita pahami di sini adalah itu

static int x = 5;

tidak sama dengan

static int x;
x = 5;

Jawaban lain telah menggunakan kata-kata penting di sini, ruang lingkup dan masa hidup, dan menunjukkan bahwa ruang lingkup xadalah dari titik deklarasinya di fungsi foohingga akhir fungsi foo. Misalnya saya memeriksa dengan memindahkan deklarasi ke akhir fungsi, dan itu membuat pernyataan xtidak dideklarasikan x++;.

Jadi bagian static int x(cakupan) dari pernyataan itu benar-benar berlaku di mana Anda membacanya, di suatu tempat DI DALAM fungsi dan hanya dari sana dan seterusnya, bukan di atasnya di dalam fungsi.

Namun bagian x = 5(seumur hidup) dari pernyataan itu adalah inisialisasi variabel dan terjadi DI LUAR fungsi sebagai bagian dari pemuatan program. Variabel xlahir dengan nilai 5saat program dimuat.

Saya membaca ini di salah satu komentar: " Juga, ini tidak membahas bagian yang benar-benar membingungkan, yaitu fakta bahwa penginisialisasi dilewati pada panggilan berikutnya. " Ini dilewati pada semua panggilan. Inisialisasi variabel berada di luar kode fungsi yang sebenarnya.

Nilai 5 secara teoritis ditetapkan terlepas dari apakah foo dipanggil atau tidak, meskipun kompilator mungkin mengoptimalkan fungsi jika Anda tidak memanggilnya di mana pun. Nilai 5 harus ada dalam variabel sebelum foo dipanggil.

Di dalam foo, pernyataan static int x = 5;itu tidak mungkin menghasilkan kode sama sekali.

Saya menemukan alamat yang xdigunakan ketika saya memasukkan fungsi fooke dalam program saya, dan kemudian (dengan benar) menebak bahwa lokasi yang sama akan digunakan jika saya menjalankan program lagi. Tangkapan layar parsial di bawah ini menunjukkan yang xmemiliki nilai 5bahkan sebelum panggilan pertama ke foo.

Break Point sebelum panggilan pertama ke foo

Ivan
sumber
2

Outputnya adalah 6 7. Variabel statis (baik di dalam fungsi atau tidak) diinisialisasi tepat satu kali, sebelum fungsi apa pun dalam unit terjemahan itu dijalankan. Setelah itu, nilainya tetap dipertahankan hingga dimodifikasi.

Jerry Coffin
sumber
1
Apakah Anda yakin statik sudah diinisialisasi sebelum fungsi dipanggil, dan bukan saat fungsi dipanggil pertama kali?
Jesse Pepper
@JessePepper: Setidaknya jika memori berfungsi, ini tergantung pada apakah Anda berbicara tentang C ++ 98/03 atau C ++ 11. Di C ++ 98/03, saya yakin itu seperti yang dijelaskan di atas. Dalam C ++ 11, threading membuat hal itu pada dasarnya tidak mungkin dilakukan, jadi inisialisasi dilakukan pada entri pertama ke fungsi tersebut.
Jerry Coffin
2
Saya pikir Anda sebenarnya salah. Saya pikir bahkan sebelum C ++ 11 itu hanya diinisialisasi ketika fungsi dipanggil. Ini penting untuk solusi umum untuk masalah ketergantungan inisialisasi statis.
Jesse Pepper
2

Vadiklk,

Kenapa ...? Alasannya adalah karena variabel statis diinisialisasi hanya sekali, dan mempertahankan nilainya di seluruh program. Artinya, Anda dapat menggunakan variabel statis antara pemanggilan fungsi. juga dapat digunakan untuk menghitung "berapa kali suatu fungsi dipanggil"

main()
{
   static int var = 5;
   printf("%d ",var--);
   if(var)
      main();
} 

dan jawabannya adalah 5 4 3 2 1 dan bukan 5 5 5 5 5 5 .... (loop tak terbatas) seperti yang Anda harapkan. Sekali lagi, alasannya adalah variabel statis diinisialisasi satu kali, ketika main () dipanggil berikutnya tidak akan diinisialisasi ke 5 karena sudah diinisialisasi dalam program. Jadi kita bisa mengubah nilainya tapi tidak bisa diinisialisasi ulang. Begitulah cara kerja variabel statis.

atau Anda dapat mempertimbangkan sesuai penyimpanan: variabel statis disimpan di Bagian Data program dan variabel yang disimpan di Bagian Data diinisialisasi satu kali. dan sebelum inisialisasi disimpan di bagian BSS.

Pada gilirannya, variabel Otomatis (lokal) disimpan di Stack dan semua variabel di stack diinisialisasi ulang sepanjang waktu ketika fungsi disebut sebagai FAR baru (catatan aktivasi fungsi) dibuat untuk itu.

oke untuk lebih memahami, lakukan contoh di atas tanpa "statis" dan beri tahu Anda apa yang akan menjadi outputnya. Itu membuat Anda memahami perbedaan antara keduanya.

Terima kasih Javed

Javed
sumber
1

Mari kita baca saja artikel Wikipedia tentang Variabel Statis ...

Variabel lokal statis: variabel yang dideklarasikan sebagai statis di dalam fungsi dialokasikan secara statis sambil memiliki cakupan yang sama dengan variabel lokal otomatis. Oleh karena itu, nilai apa pun yang dimasukkan fungsi ke dalam variabel lokal statisnya selama satu panggilan akan tetap ada saat fungsi dipanggil lagi.

Andrew White
sumber
5
Itu buruk! "variabel yang dideklarasikan sebagai statis di dalam suatu fungsi dialokasikan secara statis" - ini tidak menjelaskan apa-apa, kecuali Anda sudah tahu apa artinya!
@Blank: yah, untuk itulah saya pikir kalimat kedua adalah untuk. Meskipun saya kira Anda benar, itu seharusnya lebih baik.
Andrew White
Selain itu, ini tidak membahas bagian yang benar-benar membingungkan, yaitu fakta bahwa penginisialisasi dilewati pada panggilan berikutnya.
Tom Auger
dialokasikan secara statis berarti tidak ada tumpukan, atau tumpukan.
Bunglon
1

Anda akan mendapatkan 6 7 dicetak sebagai, seperti yang mudah diuji, dan inilah alasannya: Ketika foopertama kali dipanggil, variabel statis x diinisialisasi ke 5. Kemudian dinaikkan menjadi 6 dan dicetak.

Sekarang untuk panggilan berikutnya ke foo. Program melewatkan inisialisasi variabel statis, dan sebaliknya menggunakan nilai 6 yang ditugaskan ke x terakhir kali. Eksekusi berjalan seperti biasa, memberi Anda nilai 7.

Ken Wayne VanderLinde
sumber
1
6 7

x adalah variabel global yang hanya terlihat dari foo (). 5 adalah nilai awalnya, seperti yang disimpan di bagian .data pada kode. Setiap modifikasi berikutnya menimpa nilai sebelumnya. Tidak ada kode tugas yang dibuat di badan fungsi.

mouviciel
sumber
1

6 dan 7 Karena variabel statis diinisialisasi hanya sekali, Jadi 5 ++ menjadi 6 pada pemanggilan pertama 6 ++ menjadi 7 pada pemanggilan ke-2 Catatan-ketika pemanggilan kedua terjadi dibutuhkan nilai x adalah 6, bukan 5 karena x adalah variabel statis.

Tushar shirsath
sumber
0

Setidaknya dalam C ++ 11, ketika ekspresi yang digunakan untuk menginisialisasi variabel statis lokal bukanlah 'constexpr' (tidak dapat dievaluasi oleh compiler), maka inisialisasi harus terjadi selama panggilan pertama ke fungsi tersebut. Contoh paling sederhana adalah dengan langsung menggunakan parameter untuk menginisialisasi variabel statis lokal. Oleh karena itu, compiler harus mengeluarkan kode untuk menebak apakah panggilan tersebut yang pertama atau tidak, yang pada gilirannya membutuhkan variabel boolean lokal. Saya telah mengumpulkan contoh seperti itu dan memeriksa apakah ini benar dengan melihat kode assembly. Contohnya bisa seperti ini:

void f( int p )
{
  static const int first_p = p ;
  cout << "first p == " << p << endl ;
}

void main()
{
   f(1); f(2); f(3);
}

tentu saja, jika ekspresi adalah 'constexpr', maka ini tidak diperlukan dan variabel dapat diinisialisasi pada pemuatan program dengan menggunakan nilai yang disimpan oleh compiler dalam kode assembly output.

pengguna5122888
sumber