Ketika melakukan refactoring beberapa #defines
saya menemukan deklarasi yang mirip dengan berikut ini di file header C ++:
static const unsigned int VAL = 42;
const unsigned int ANOTHER_VAL = 37;
Pertanyaannya adalah, apa bedanya, jika ada, yang akan dihasilkan oleh statis? Perhatikan bahwa beberapa penyertaan header tidak dimungkinkan karena #ifndef HEADER
#define HEADER
#endif
trik klasik (jika itu penting).
Apakah statik berarti hanya satu salinan VAL
yang dibuat, jika header disertakan oleh lebih dari satu file sumber?
Jawaban:
The
static
berarti bahwa akan ada satu salinan dariVAL
dibuat untuk setiap file sumber itu termasuk dalam. Tetapi juga berarti bahwa beberapa inklusi tidak akan menghasilkan beberapa definisiVAL
yang akan bertabrakan pada link waktu. Di C, tanpastatic
Anda perlu memastikan bahwa hanya satu file sumber yang ditentukanVAL
sedangkan file sumber lainnya mendeklarasikannyaextern
. Biasanya seseorang akan melakukan ini dengan mendefinisikannya (mungkin dengan penginisialisasi) dalam file sumber dan meletakkanextern
deklarasi di file header.static
variabel di tingkat global hanya terlihat di file sumbernya sendiri apakah variabel tersebut sampai di sana melalui penyertaan atau berada di file utama.Catatan editor: Dalam C ++,
const
objek tanpa kata kuncistatic
norextern
dalam deklarasinya secara implisitstatic
.sumber
The
static
danextern
tag pada variabel-file scoped menentukan apakah mereka dapat diakses dalam unit terjemahan lain (yaitu lain.c
atau.cpp
file).static
memberikan hubungan internal variabel, menyembunyikannya dari unit terjemahan lain. Namun, variabel dengan tautan internal dapat ditentukan dalam beberapa unit terjemahan.extern
memberikan hubungan eksternal variabel, membuatnya terlihat oleh unit terjemahan lain. Biasanya ini berarti bahwa variabel hanya harus ditentukan dalam satu unit terjemahan.Defaultnya (ketika Anda tidak menentukan
static
atauextern
) adalah salah satu area di mana C dan C ++ berbeda.Di C, variabel cakupan file adalah
extern
(tautan eksternal) secara default. Jika Anda menggunakan C,VAL
isstatic
danANOTHER_VAL
isextern
.Dalam C ++, variabel cakupan file adalah
static
(tautan internal) secara default jika adaconst
, danextern
secara default jika tidak. Jika Anda menggunakan C ++,VAL
danANOTHER_VAL
arestatic
.Dari draf spesifikasi C :
Dari draf spesifikasi C ++ :
sumber
Statis akan berarti Anda mendapatkan satu salinan per file, tetapi tidak seperti yang lain mengatakan itu legal untuk melakukannya. Anda dapat dengan mudah mengujinya dengan contoh kode kecil:
test.h:
static int TEST = 0; void test();
test1.cpp:
#include <iostream> #include "test.h" int main(void) { std::cout << &TEST << std::endl; test(); }
test2.cpp:
#include <iostream> #include "test.h" void test() { std::cout << &TEST << std::endl; }
Menjalankan ini memberi Anda keluaran ini:
sumber
TEST
adaconst
, apakah LTO akan dapat mengoptimalkannya ke dalam satu lokasi memori. Tapi-O3 -flto
GCC 8.1 tidak.const
variabel di C ++ memiliki keterkaitan internal. Jadi, penggunaanstatic
tidak berpengaruh.ah
const int i = 10;
one.cpp
#include "a.h" func() { cout << i; }
two.cpp
#include "a.h" func1() { cout << i; }
Jika ini adalah program C, Anda akan mendapatkan kesalahan 'definisi ganda' untuk
i
(karena tautan eksternal).sumber
static
memiliki efek yang dengan rapi menandakan niat dan kesadaran tentang apa yang dikodekan, yang tidak pernah merupakan hal yang buruk. Bagi saya ini sepertivirtual
saat menimpa: kita tidak perlu melakukannya, tetapi segala sesuatunya terlihat jauh lebih intuitif - dan konsisten dengan pernyataan lain - saat kita melakukannya.Deklarasi statis pada level kode ini berarti bahwa variabel tersebut hanya terlihat di unit kompilasi saat ini. Ini berarti bahwa hanya kode dalam modul itu yang akan melihat variabel itu.
jika Anda memiliki file header yang mendeklarasikan variabel statis dan header tersebut disertakan dalam beberapa file C / CPP, variabel tersebut akan menjadi "lokal" untuk modul tersebut. Akan ada N salinan variabel itu untuk N tempat header itu disertakan. Mereka sama sekali tidak terkait satu sama lain. Kode apa pun dalam salah satu file sumber tersebut hanya akan mereferensikan variabel yang dideklarasikan dalam modul itu.
Dalam kasus khusus ini, kata kunci 'statis' tampaknya tidak memberikan manfaat apa pun. Saya mungkin melewatkan sesuatu, tetapi tampaknya tidak masalah - Saya belum pernah melihat yang dilakukan seperti ini sebelumnya.
Sedangkan untuk sebaris, dalam hal ini variabel kemungkinan besar sebaris, tapi itu hanya karena itu dinyatakan const. Kompiler mungkin lebih cenderung memasukkan variabel statis modul, tetapi itu tergantung pada situasi dan kode yang sedang dikompilasi. Tidak ada jaminan bahwa kompilator akan menyebariskan 'statika'.
sumber
const
, makastatic
tersirat dan karenanya opsional. Konsekuensinya adalah bahwa tidak ada kerentanan terhadap kesalahan definisi ganda seperti yang diklaim Mike F.Buku C (online gratis) memiliki bab tentang linkage, yang menjelaskan arti 'statis' secara lebih rinci (walaupun jawaban yang benar sudah diberikan di komentar lain): http://publications.gbdirect.co.uk/c_book /chapter4/linkage.html
sumber
Untuk menjawab pertanyaan, "apakah statik berarti hanya satu salinan VAL yang dibuat, jika header disertakan oleh lebih dari satu file sumber?" ...
TIDAK . VAL akan selalu didefinisikan secara terpisah di setiap file yang menyertakan header.
Standar untuk C dan C ++ memang menyebabkan perbedaan dalam kasus ini.
Perhatikan bahwa penaut modern mungkin mengeluh tentang ANOTHER_VAL jika header disertakan dalam file berbeda (nama global yang sama ditentukan dua kali), dan pasti akan mengeluh jika ANOTHER_VAL diinisialisasi ke nilai yang berbeda di file lain
Anda juga perlu memperhitungkan fakta bahwa kedua variabel ditetapkan sebagai konst. Idealnya kompilator akan selalu memilih untuk menyebariskan variabel-variabel ini dan tidak menyertakan penyimpanan apa pun untuknya. Ada banyak sekali alasan mengapa penyimpanan dapat dialokasikan. Yang terpikir olehku ...
sumber
Dengan asumsi bahwa deklarasi ini berada pada cakupan global (yaitu bukan variabel anggota), maka:
statis berarti 'hubungan internal'. Dalam kasus ini, karena dideklarasikan const, ini dapat dioptimalkan / dimasukkan oleh compiler. Jika Anda menghilangkan const maka compiler harus mengalokasikan penyimpanan di setiap unit kompilasi.
Dengan menghilangkan statis , linkage secara default adalah eksternal . Sekali lagi, Anda telah disimpan oleh konst ness - kompilator dapat mengoptimalkan / penggunaan sebaris. Jika Anda menjatuhkan konstanta maka Anda akan mendapatkan kesalahan simbol multiply didefinisikan pada waktu tautan.
sumber
Anda tidak dapat mendeklarasikan variabel statis tanpa mendefinisikannya juga (ini karena pengubah kelas penyimpanan statis dan eksternal saling eksklusif). Variabel statis dapat didefinisikan dalam file header, tetapi ini akan menyebabkan setiap file sumber yang menyertakan file header memiliki salinan variabelnya sendiri, yang mungkin bukan yang dimaksudkan.
sumber
Variabel const secara default statis di C ++, tetapi ekstern C. Jadi, jika Anda menggunakan C ++, konstruksi apa yang harus digunakan.
(7.11.6 C ++ 2003, dan Apexndix C memiliki sampel)
Contoh dalam membandingkan sumber kompilasi / tautan sebagai program C dan C ++:
bruziuz:~/test$ cat a.c const int b = 22; int main(){return 0;} bruziuz:~/test$ cat b.c const int b=2; bruziuz:~/test$ gcc -x c -std=c89 a.c b.c /tmp/ccSKKIRZ.o:(.rodata+0x0): multiple definition of `b' /tmp/ccDSd0V3.o:(.rodata+0x0): first defined here collect2: error: ld returned 1 exit status bruziuz:~/test$ gcc -x c++ -std=c++03 a.c b.c bruziuz:~/test$ bruziuz:~/test$ gcc --version | head -n1 gcc (Ubuntu 5.4.0-6ubuntu1~16.04.5) 5.4.0 20160609
sumber
static
. Ini menandakan niat / kesadaran tentang apa yang dilakukan programmer dan mempertahankan paritas dengan jenis deklarasi lain (dan, fwiw, C) yang tidak memiliki implisitstatic
. Ini seperti menyertakanvirtual
dan akhir-akhir inioverride
dalam deklarasi fungsi utama - tidak perlu, tetapi lebih banyak mendokumentasikan diri sendiri dan, dalam kasus yang terakhir, kondusif untuk analisis statis.const
hanya digunakan pada variabel di header dengang++ (GCC) 7.2.1 20170915 (Red Hat 7.2.1-2)
. Ini menghasilkan sekitar 150 simbol multiply didefinisikan (satu untuk setiap unit terjemahan tajuk disertakan). Saya pikir kita membutuhkan keduanyastatic
,inline
atau namespace anonim / tidak bernama untuk menghindari hubungan eksternal.const int
di dalam ruang lingkup namespace dan di namespace global. Dan itu dikompilasi dan mengikuti aturan "Objek menyatakan const dan tidak secara eksplisit dinyatakan eksternal memiliki hubungan internal." ".... Mungkin dalam proyek dalam beberapa alasan header ini dimasukkan ke dalam sumber yang dikompilasi C, di mana aturan yang sama sekali berbeda.Statis mencegah unit kompilasi lain untuk mengeluarkan variabel tersebut sehingga kompilator bisa "menyebariskan" nilai variabel di mana ia digunakan dan tidak membuat penyimpanan memori untuknya.
Dalam contoh kedua, kompilator tidak dapat berasumsi bahwa beberapa file sumber lain tidak akan mengeluarkannya, jadi ia harus benar-benar menyimpan nilai itu dalam memori di suatu tempat.
sumber
Statis mencegah kompilator menambahkan banyak contoh. Ini menjadi kurang penting dengan perlindungan #ifndef, tetapi dengan asumsi header disertakan dalam dua pustaka terpisah, dan aplikasi ditautkan, dua contoh akan disertakan.
sumber
static
"kurang penting". dan bahkan dengan keduanya, Anda bisa mendapatkan beberapa definisi yang terhubung secara internal, yang mungkin tidak dimaksudkan.