Ini memiliki kegunaan di C dan C ++.
Seperti yang Anda duga, static
bagian tersebut membatasi cakupannya pada unit kompilasi tersebut . Ini juga menyediakan inisialisasi statis. const
hanya memberitahu kompilator untuk tidak membiarkan siapa pun memodifikasinya. Variabel ini diletakkan di segmen data atau bss tergantung pada arsitekturnya, dan mungkin berada dalam memori bertanda hanya-baca.
Semua itu adalah bagaimana C memperlakukan variabel ini (atau bagaimana C ++ memperlakukan variabel namespace). Di C ++, anggota yang ditandai static
dibagikan oleh semua instance kelas tertentu. Entah itu privat atau tidak, tidak memengaruhi fakta bahwa satu variabel digunakan bersama oleh banyak contoh. Setelah const
di sana akan memperingatkan Anda jika ada kode yang mencoba memodifikasi itu.
Jika itu benar-benar pribadi, maka setiap instance kelas akan mendapatkan versinya sendiri (terlepas dari pengoptimal).
Banyak orang memberikan jawaban dasar tetapi tidak ada yang menunjukkan bahwa dalam C ++
const
defaultstatic
padanamespace
tingkat (dan beberapa memberikan informasi yang salah). Lihat standar C ++ 98 bagian 3.5.3.Pertama beberapa latar belakang:
Unit terjemahan: File sumber setelah pra-prosesor (secara rekursif) menyertakan semua file yang disertakan.
Kaitan statis: Simbol hanya tersedia di dalam unit terjemahannya.
Keterkaitan eksternal: Simbol tersedia dari unit terjemahan lain.
Di
namespace
levelIni termasuk namespace global alias variabel global .
Di tingkat fungsi
static
berarti nilainya dipertahankan di antara panggilan fungsi.Semantik
static
variabel fungsi mirip dengan variabel global karena berada di segmen data program (dan bukan tumpukan atau tumpukan), lihat pertanyaan ini untuk detail selengkapnya tentangstatic
masa pakai variabel.Di
class
levelstatic
artinya nilai tersebut dibagi antara semua instance kelas danconst
artinya tidak berubah.sumber
const int *foo(int x) {const int b=x;return &b};
dibandingkanconst int *foo(int x) {static const int b=x;return &b};
const
hanya menyiratkanstatic
di C ++ .const
deklarasi juga mengandung artistatic
? Seperti, jika Anda membuangconst
, dan mengubah nilainya, semua nilai akan diubah?const
tidak menyiratkan statis pada tingkat fungsi, itu akan menjadi mimpi buruk konkurensi (konst! = Ekspresi konstan), semua yang ada di tingkat fungsi secara implisitauto
. Karena pertanyaan ini juga diberi tag [c], saya harus menyebutkan bahwa tingkat globalconst int
secara implisit adaextern
di C. Namun, aturan yang Anda miliki di sini menjelaskan C ++ dengan sempurna.static
menunjukkan bahwa variabel adalah durasi statis (hanya ada satu salinan, yang berlangsung dari awal program hingga akhir), dan memiliki tautan internal / statis jika tidak ditentukan lain (ini diganti oleh fungsi linkage untuk variabel statis lokal, atau linkage kelas untuk anggota statis). Perbedaan utama terletak pada apa yang tersirat dalam setiap situasistatic
yang valid.Baris kode tersebut sebenarnya dapat muncul dalam beberapa konteks berbeda dan meskipun perilakunya kira-kira sama, ada perbedaan kecil.
Cakupan Namespace
'
i
' akan terlihat di setiap unit terjemahan yang menyertakan tajuk. Namun, kecuali Anda benar-benar menggunakan alamat objek (misalnya. '&i
'), Saya cukup yakin bahwa kompilator akan memperlakukan 'i
' hanya sebagai tipe aman0
. Jika dua unit terjemahan lagi menggunakan '&i
' maka alamatnya akan berbeda untuk setiap unit terjemahan.'
i
' memiliki hubungan internal, sehingga tidak dapat dirujuk dari luar unit terjemahan ini. Namun, sekali lagi kecuali Anda menggunakan alamatnya, kemungkinan besar akan diperlakukan sebagai tipe-aman0
.Satu hal yang perlu diperhatikan, adalah pernyataan berikut:
adalah persis sama dengan
static const int i = 0
. Variabel dalam namespace yang dideklarasikan denganconst
dan tidak secara eksplisit dideklarasikan denganextern
statis secara implisit. Jika Anda memikirkan hal ini, komite C ++ bermaksud untuk mengizinkanconst
variabel dideklarasikan dalam file header tanpa selalu memerlukanstatic
kata kunci untuk menghindari kerusakan ODR.Ruang Lingkup Kelas
Dalam contoh di atas, standar secara eksplisit menetapkan bahwa '
i
' tidak perlu ditentukan jika alamatnya tidak diperlukan. Dengan kata lain jika Anda hanya menggunakan 'i
' sebagai tipe-aman 0 maka kompilator tidak akan mendefinisikannya. Satu perbedaan antara versi kelas dan namespace adalah bahwa alamat 'i
' (jika digunakan dalam dua atau lebih unit terjemahan) akan sama untuk anggota kelas. Jika alamat digunakan, Anda harus memiliki definisinya:sumber
Ini adalah pengoptimalan ruang kecil.
Saat Anda berkata
Anda tidak mendefinisikan sebuah konstanta, tetapi membuat variabel hanya-baca. Kompilator cukup pintar untuk menggunakan 42 setiap kali ia melihat foo, tetapi ia juga akan mengalokasikan ruang di area data yang diinisialisasi untuknya. Ini dilakukan karena, sebagaimana didefinisikan, foo memiliki keterkaitan eksternal. Unit kompilasi lain dapat mengatakan:
extern const int foo;
Untuk mendapatkan akses ke nilainya. Itu bukan praktik yang baik karena unit kompilasi itu tidak tahu apa nilai foo. Itu hanya tahu itu adalah const int dan harus memuat ulang nilai dari memori setiap kali digunakan.
Sekarang, dengan menyatakan bahwa itu statis:
Kompilator dapat melakukan pengoptimalan seperti biasa, tetapi ia juga dapat berkata "hei, tidak ada orang di luar unit kompilasi ini yang dapat melihat foo dan saya tahu selalu 42 sehingga tidak perlu mengalokasikan ruang untuk itu."
Saya juga harus mencatat bahwa di C ++, cara yang disukai untuk mencegah nama keluar dari unit kompilasi saat ini adalah dengan menggunakan namespace anonim:
sumber
Ini kehilangan 'int'. Harus:
Di C dan C ++, ia mendeklarasikan konstanta integer dengan cakupan file lokal bernilai 42.
Mengapa 42? Jika Anda belum mengetahuinya (dan sulit dipercaya bahwa Anda belum mengetahuinya), ini merujuk pada Jawaban atas Kehidupan, Semesta, dan Segalanya .
sumber
Di C ++,
adalah cara yang lebih disukai untuk mendefinisikan & menggunakan konstanta. Yaitu menggunakan ini daripada
karena tidak merusak sistem keamanan tipe.
sumber
Untuk semua jawaban hebat, saya ingin menambahkan detail kecil:
Jika Anda menulis plugin (mis. DLL atau pustaka .so untuk dimuat oleh sistem CAD), maka statis adalah penyelamat yang menghindari benturan nama seperti ini:
Lebih buruk lagi: Langkah 3 mungkin berperilaku berbeda tergantung pada pengoptimalan kompiler, mekanisme pemuatan plugin, dll.
Saya mengalami masalah ini sekali dengan dua fungsi pembantu (nama yang sama, perilaku berbeda) di dua plugin. Mendeklarasikan mereka statis memecahkan masalah.
sumber
Menurut spesifikasi C99 / GNU99:
static
adalah penentu kelas penyimpanan
objek lingkup tingkat file secara default memiliki hubungan eksternal
const
adalah type-qualifier (merupakan bagian dari type)
Kata kunci diterapkan ke contoh kiri langsung - yaitu
MyObj const * myVar;
- penunjuk yang tidak memenuhi syarat ke tipe objek yang memenuhi syaratMyObj * const myVar;
- const pointer yang memenuhi syarat ke tipe objek yang tidak memenuhi syaratPenggunaan paling kiri - diterapkan pada tipe objek, bukan variabel
const MyObj * myVar;
- penunjuk yang tidak memenuhi syarat ke tipe objek yang memenuhi syaratJADI:
static NSString * const myVar;
- penunjuk konstan ke string yang tidak dapat diubah dengan hubungan internal.Tidak adanya
static
kata kunci akan membuat nama variabel menjadi global dan dapat menyebabkan konflik nama dalam aplikasi.sumber
inline
Variabel C ++ 17Jika Anda mencari "C ++ const static" di Google, kemungkinan besar yang benar-benar ingin Anda gunakan adalah variabel inline C ++ 17 .
Fitur C ++ 17 yang luar biasa ini memungkinkan kita untuk:
constexpr
: Bagaimana cara mendeklarasikan constexpr extern?main.cpp
notmain.hpp
notmain.cpp
Kompilasi dan jalankan:
GitHub upstream .
Lihat juga: Bagaimana cara kerja variabel sebaris?
Standar C ++ pada variabel sebaris
Standar C ++ menjamin bahwa alamatnya akan sama. C ++ 17 N4659 standard draft 10.1.6 "The inline specifier":
cppreference https://en.cppreference.com/w/cpp/language/inline menjelaskan bahwa jika
static
tidak diberikan, maka ia memiliki tautan eksternal.Penerapan variabel sebaris GCC
Kita dapat mengamati bagaimana ini diterapkan dengan:
yang mengandung:
dan
man nm
mengatakan tentangu
:jadi kami melihat bahwa ada ekstensi ELF khusus untuk ini.
Pra-C ++ 17:
extern const
Sebelum C ++ 17, dan di C, kita dapat mencapai efek yang sangat mirip dengan sebuah
extern const
, yang akan mengarah ke satu lokasi memori yang digunakan.Kerugiannya
inline
adalah:constexpr
dengan teknik ini, hanyainline
memungkinkan: Bagaimana cara mendeklarasikan constexpr extern?main.cpp
notmain.cpp
notmain.hpp
GitHub upstream .
Alternatif header saja Pre-C ++ 17
Ini tidak sebaik
extern
solusinya, tetapi berfungsi dan hanya menggunakan satu lokasi memori:Sebuah
constexpr
fungsi, karenaconstexpr
menyiratkaninline
daninline
memungkinkan (memaksa) definisi tersebut muncul di setiap unit terjemahan :dan saya yakin bahwa setiap kompiler yang layak akan melakukan panggilan inline.
Anda juga dapat menggunakan variabel
const
atauconstexpr
statis seperti di:tetapi Anda tidak dapat melakukan hal-hal seperti mengambil alamatnya, atau menjadi digunakan odr, lihat juga: Mendefinisikan anggota data statis constexpr
C
Dalam C situasinya sama dengan C ++ sebelum C ++ 17, saya telah mengunggah contoh di: Apa artinya "statis" di C?
Satu-satunya perbedaan adalah bahwa dalam C ++,
const
menyiratkanstatic
untuk GLOBALS, tapi tidak di C: C ++ semantik `const` statis vs` const`Adakah cara untuk membuatnya sebaris sepenuhnya?
TODO: apakah ada cara untuk menyebariskan variabel sepenuhnya, tanpa menggunakan memori sama sekali?
Mirip seperti yang dilakukan preprocessor.
Ini akan membutuhkan entah bagaimana:
Terkait:
Diuji di Ubuntu 18.10, GCC 8.2.0.
sumber
Ya, itu menyembunyikan variabel dalam modul dari modul lain. Di C ++, saya menggunakannya ketika saya tidak ingin / perlu mengubah file .h yang akan memicu pembuatan ulang file lain yang tidak perlu. Juga, saya menempatkan statis terlebih dahulu:
Selain itu, bergantung pada penggunaannya, compiler bahkan tidak akan mengalokasikan penyimpanan untuknya dan hanya "menyebariskan" nilai tempatnya digunakan. Tanpa statik, kompilator tidak dapat menganggap itu tidak digunakan di tempat lain dan tidak bisa sebaris.
sumber
Konstanta global ini hanya terlihat / dapat diakses dalam modul kompilasi (file .cpp). BTW yang menggunakan statis untuk tujuan ini tidak digunakan lagi. Lebih baik gunakan namespace anonim dan enum:
sumber
enum
dimiliki dalam konteks ini. Mau menjelaskan lebih lanjut? Halenums
tersebut biasanya hanya digunakan untuk mencegah kompilator mengalokasikan ruang apa pun untuk nilai tersebut (meskipun kompiler modern tidak memerlukanenum
peretasan ini untuk itu) dan untuk mencegah pembuatan pointer ke nilai.Menjadikannya pribadi tetap berarti itu muncul di header. Saya cenderung menggunakan cara "terlemah" yang berhasil. Lihat artikel klasik ini oleh Scott Meyers: http://www.ddj.com/cpp/184401197 (ini tentang fungsi, tetapi dapat diterapkan di sini juga).
sumber