Apakah variabel `static` file-scope dalam C seburuk variabel global` extern`?


8

Dalam C, Anda akan sering / kadang-kadang (karena gaya) menggunakan staticvariabel lingkup file di mana Anda akan menggunakan variabel anggota kelas pribadi di C ++. Saat melakukan penskalaan ke program multithreaded, cukup menambahkan thread_localC11 atau ekstensi yang didukung lama __threadcocok. Saya tahu Anda bisa melakukan hal yang persis sama dalam C sebagai C ++ dengan meletakkan segala sesuatu di dalam structdan membuat satu set fungsi yang mengambil pointer ke itu structsebagai argumen pertama. Beberapa perpustakaan melakukan ini secara ekstensif. Tapi gaya pribadi saya adalah menjaga structsekecil mungkin, jika perlu.

Saya sering membaca atau mendengar beberapa orang yang memperdebatkan variabel 'global' sangat buruk. Saya mengikuti alasan mereka, dan sebagian besar argumen mereka tampaknya terkait dengan externvariabel global dalam istilah C. Apa yang mereka katakan tentu benar. Saya kadang-kadang menggunakan 1 atau 2 externvariabel yang dideklarasikan di seluruh program ketika akan menyederhanakan banyak hal dan ketika mudah untuk melacaknya, tetapi melangkah lebih jauh akan dengan mudah membuat program tidak dapat diprediksi.

Bagaimana dengan staticvariabel? Apakah mereka masih memiliki masalah yang sama dengan variabel global 'nyata'? Mungkin saya bahkan tidak perlu mengajukan pertanyaan ini dan melanjutkan jika saya pikir apa yang saya lakukan adalah benar, tetapi hari ini saya melihat jenis posting 'variabel global yang BURUK' lainnya, dan akhirnya datang ke sini berpikir mungkin ini adalah hak tempat untuk pertanyaan semacam itu. Apa yang kamu pikirkan?

Pertanyaan ini bukan merupakan duplikat dari ini karena pertanyaan ini menanyakan tentang externdan staticvariabel non-lokal sedangkan pertanyaan lainnya adalah tentang variabel file-lingkup dan blok-lingkup static.



3
Saya rasa ini bukan duplikat. Pertanyaan ini menanyakan tentang variabel file-statis dibandingkan dengan variabel eksternal (global) statis. Pertanyaan lainnya adalah membandingkan variabel fungsi-statis dengan variabel global.

@gnat Ini bukan pertanyaan rangkap. Saya telah mengedit untuk menjelaskan bahwa pada dasarnya mengatakan apa yang dikatakan Snowman dalam komentarnya. Bahkan judulnya pun berbeda.
xiver77

@ xiver77 sementara saat ini tidak ada suara untuk ditutup sebagai duplikat, beberapa jawaban pada pertanyaan lain mungkin berwawasan luas di sini.

@Snowman per bacaan saya, jawaban yang diterima dalam pertanyaan lain mencakup ketiga kasus (tampaknya untuk menjelaskan kapan dan mengapa statika ruang lingkup file lebih disukai daripada yang scoped fungsi dan global)
agung

Jawaban:


17

Dalam program C yang dirancang dengan baik, variabel file-statis mirip dengan anggota statis pribadi kelas:

  • Itu hanya dapat diakses oleh fungsi-fungsi dalam file itu, mirip dengan bagaimana variabel anggota statis pribadi hanya dapat diakses oleh fungsi-fungsi di kelas di mana ia didefinisikan.

  • Hanya ada satu salinan variabel.

  • Masa hidupnya adalah masa hidup program.

Suatu externvariabel akan menjadi variabel global sejati seperti dalam bahasa apa pun yang mendukungnya.

Sebuah staticvariabel non-global tidak seburuk global; sebenarnya, mereka diperlukan dalam beberapa kasus.

  • Akses dikendalikan melalui fungsi yang Anda tulis. Ini membantu dengan integritas data termasuk pemeriksaan batas serta keamanan utas. (catatan: ini tidak menjamin keamanan utas, ini hanyalah satu alat untuk membantu di sepanjang jalan)

  • Data dienkapsulasi: hanya file yang dapat mengaksesnya. Ini sedekat C dapat enkapsulasi di mana beberapa fungsi dapat mengakses variabel statis.

Variabel global buruk apa pun yang terjadi. Variabel file statis memiliki manfaat dari variabel statis pribadi tetapi tidak ada kelemahan dari variabel global.

Satu-satunya masalah tidak seperti dengan variabel statis pribadi yang benar seperti dalam C ++, file lain dapat mendeklarasikan externvariabel yang cocok dengan deklarasi dan Anda tidak dapat mencegah akses. Dengan kata lain, Anda mengandalkan sistem kehormatan untuk menghindari mengubahnya menjadi variabel global.


6

Status global, termasuk externvariabel dan non- const staticvariabel dalam cakupan file atau fungsi seringkali dapat menjadi solusi mudah untuk masalah yang diberikan, tetapi ada tiga masalah:

  1. staticmembuat kode tidak dapat diuji , karena staticvariabel cenderung dependensi yang tidak dapat diganti. Atau dengan kata lain OOP-y: Anda tidak mengikuti Prinsip Ketergantungan Pembalikan. Saya datang ke C dan C ++ dari bahasa dinamis seperti Perl, jadi model biaya saya condong ke arah pengiriman virtual dan fungsi pointer dan sebagainya. Dengan bahasa saat ini, ada beberapa konflik antara testabilitas dan arsitektur yang baik, tapi saya pikir gangguan kecil membuat dependensi Anda eksplisit dan membiarkannya ditimpa dalam tes secara nyata diimbangi oleh kemudahan tes menulis, dan dengan demikian memastikan perangkat lunak Anda berfungsi sebagai diharapkan. Tanpa membuat kode Anda lebih dinamis, satu-satunya mekanisme yang tersedia untuk menyuntikkan dependensi untuk pengujian adalah kompilasi bersyarat.

  2. Status global mempersulit alasan tentang kebenaran , dan itu mengarah pada bug. Semakin banyak bit dan potongan memiliki akses ke variabel dan dapat memodifikasinya, semakin mudah kehilangan jejak apa yang terjadi. Sebaliknya: lebih suka penugasan variabel tunggal! Lebih suka constdimanapun yang masuk akal! Lebih suka menjaga variabel melalui getter dan setter di mana Anda dapat memperkenalkan pemeriksaan kebenaran. Selama negara itu staticdan tidak extern, itu masih mungkinuntuk mempertahankan kebenaran, tetapi selalu lebih baik untuk menganggap saya-dalam-seminggu tidak akan secerdas saya-sekarang. Terutama di C ++, kita dapat menggunakan kelas untuk memodelkan berbagai abstraksi yang membuatnya tidak mungkin untuk menyalahgunakan sesuatu, jadi cobalah untuk menggunakan sistem tipe daripada kecerdasan Anda - Anda memiliki hal-hal yang lebih penting untuk dipikirkan.

  3. Negara global mungkin menyiratkan bahwa fungsi Anda tidak masuk kembali , atau bahwa mereka hanya dapat digunakan dalam satu konteks pada suatu waktu. Bayangkan driver basis data yang hanya bisa mengelola satu koneksi! Itu batasan yang sama sekali tidak perlu. Pada kenyataannya, keterbatasan seringkali lebih halus, seperti variabel global yang digunakan untuk mengagregasi hasil. Alih-alih, buat aliran data Anda eksplisit dan lewati semuanya melalui parameter fungsi. Sekali lagi, kelas C ++ dapat membuat ini lebih mudah dikelola.

Jelas, static const NAMED_CONSTANTStidak apa-apa. Menggunakan staticfungsi-fungsi di dalam adalah jauh lebih rumit: walaupun berguna untuk konstanta yang diinisialisasi dengan malas, ini mungkin cukup tidak dapat diuji coba. Kompromi adalah memisahkan menghitung nilai awal dari variabel statis, sehingga kedua bagian dapat diuji secara terpisah.

Dalam program kecil dan mandiri, semua ini tidak masalah, dan Anda dapat terus menggunakan statickeadaan untuk menyenangkan hati Anda. Tetapi ketika Anda melewati sekitar 500 LOC atau jika Anda menulis perpustakaan yang dapat digunakan kembali, Anda harus benar-benar mulai berpikir tentang arsitektur yang baik dan antarmuka yang baik tanpa batasan yang tidak perlu.


Beberapa saran Anda tentang desain dan keselamatan kadang-kadang tidak mungkin untuk diperhatikan dalam program yang perlu ditulis dalam C.
xiver77

Dan negara global tidak serta merta tidak ramah. Standar C dan C ++ terbaru yang dimiliki thread_localdan kompiler telah lama mendukungnya sebagai ekstensi sebelum standardisasi.
xiver77

Untuk menghindari banyak masalah negara global yang Anda sebutkan, sebagian besar program C yang ditulis dengan baik memiliki struktur yang dangkal dan transparan dengan meminimalkan ketergantungan luar.
xiver77

Menjaga kode statis dan data dapat berubah, sementara rawan bug, adalah satu-satunya cara untuk menulis program yang paling efisien dalam arsitektur komputer saat ini.
xiver77

@ xiver77 Saya memiliki kemewahan menulis lebih banyak kode tingkat tinggi, jadi tidak mengorbankan arsitektur untuk kinerja atau menggunakan C diperlukan dalam pekerjaan saya :) Ketika menulis C, saya merasa jauh lebih sulit untuk menulis kode yang benar, dan pilihannya abstraksi yang cocok berbeda dari apa yang saya inginkan, tetapi masih mungkin untuk memberikan banyak keamanan. Jawaban saya mencoba menandai dengan jelas C ++ - ide spesifik seperti itu. Maksud Anda tentang file kecil sangat baik, yang membuatnya lebih mudah untuk alasan tentang program dan mengurangi tetapi tidak menghilangkan masalah yang ditimbulkan oleh staticvariabel.
amon

1

Saya tidak menganggap variabel dengan cakupan file seburuk variabel global. Bagaimanapun, semua akses ke variabel-variabel ini terbatas pada satu file sumber tunggal. Dengan pembatasan itu, variabel lingkup file hampir sama baiknya atau buruk dengan anggota data statis C ++ pribadi, dan Anda tidak melarang penggunaannya, bukan?


1
Dalam c ++, jenis sintaks mendorong Anda untuk meletakkan banyak variabel anggota di kelas, sehingga memiliki anggota statis pribadi tidak sering dibutuhkan. Tetapi dalam C, jika Anda tidak akan sepenuhnya meniru apa yang akan Anda lakukan dengan kelas C ++, variabel statis atau thread_local dapat digunakan sebagai pengganti anggota struct jika Anda ingin menghindari melewati penunjuk struct di mana-mana. Pertanyaan saya adalah tentang ini.
xiver77

Saya berbicara tentang anggota dengan staticpenyimpanan, yang ada tepat sekali, bukan untuk setiap objek. Variabel ini tidak memerlukan turunan kelas apa pun untuk direferensikan oleh kode kelas, sehingga tidak perlu melewati referensi / pointer ke singleton. Inilah yang dicapai variabel lingkup file juga. Satu-satunya perbedaan adalah, bahwa staticanggota memiliki ruang lingkup kelas sedangkan staticvariabel "global" memiliki ruang lingkup file. Namun kedua cakupan ini sangat mirip, yang merupakan poin saya. Saya setuju bahwa arti yang berbeda staticmembingungkan.
cmaster - mengembalikan monica

1
Setidaknya dalam C, static benar-benar memiliki satu makna untuk variabel (bukan untuk fungsi).
xiver77

1

Itu semua terkait dengan ruang lingkup variabel (tidak konstan, sesuatu yang bisa berubah) dalam pandangan saya. Ini adalah pandangan yang diakui kurang bernuansa, tetapi ini adalah kontra pragmatis dan seruan untuk kembali ke dasar-dasar paling mendasar bagi mereka yang berkata, "Ini benar-benar jahat!" hanya untuk kemudian tersandung pada masalah yang mirip dengan yang terkait dengan apa yang mereka kritik, seperti kondisi ras.

Bayangkan Anda memiliki fungsi 50.000 baris dengan segala macam variabel yang dideklarasikan di atas dan gotopernyataan untuk berkeliling di semua tempat. Itu tidak terlalu menyenangkan dengan ruang lingkup variabel yang mengerikan, dan mencoba menjelaskan fungsi, dan apa yang terjadi dengan variabel-variabel tersebut, akan menjadi sangat sulit. Dalam kasus mengerikan seperti itu, perbedaan normal antara efek samping "eksternal" dan "internal" kehilangan banyak tujuan praktisnya.

Bayangkan Anda memiliki program sederhana 80-baris yang baru saja Anda tulis satu kali dan engkol dengan variabel global (baik dengan tautan internal dan ruang lingkup file atau tautan eksternal, tetapi bagaimanapun programnya masih kecil). Itu tidak terlalu buruk.

Bayangkan Anda memiliki kelas mengerikan dalam bahasa berorientasi objek yang berisi logika seluruh program Anda dengan ribuan dan ribuan baris kode untuk implementasinya. Dalam hal ini variabel anggotanya lebih bermasalah daripada global dalam program 80-garis di atas.

Jika Anda ingin dapat alasan yang lebih baik dan lebih percaya diri tentang kode Anda, keamanan utasnya (atau ketiadaan), membuatnya lebih dapat diprediksi, pastikan pengujian Anda memiliki cakupan yang baik tanpa semua jenis kasus tepi potensial terlewatkan, dll. , lalu membantu mempersempit akses ke variabel.

Statika ruang lingkup file akan cenderung memiliki ruang lingkup yang lebih sempit daripada yang memiliki hubungan eksternal, tetapi sekali lagi jika file sumber Anda 100.000 baris kode, itu masih sangat lebar. Jadi untuk statika ruang lingkup file, jika Anda tidak dapat menghindarinya, saya akan mencoba untuk menjaga ruang lingkup mereka sempit dengan tidak membuat file sumber Anda yang dapat mengaksesnya ginormous, karena dalam hal itu mengurangi ruang lingkupnya adalah tentang mengurangi ukuran dan cakupan desain file sumber, yang bertentangan dengan fungsi (untuk variabel lokal, termasuk parameter), kelas (untuk variabel anggota), atau mungkin modul (untuk global dengan tautan eksternal tetapi hanya dapat diakses dalam modul), atau bahkan seluruh perangkat lunak (untuk global dengan hubungan eksternal dapat diakses oleh seluruh perangkat lunak).

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.