Saya telah melihat kata yang static
digunakan di berbagai tempat dalam kode C; apakah ini seperti fungsi / kelas statis di C # (di mana implementasi dibagikan di seluruh objek)?
Saya telah melihat kata yang static
digunakan di berbagai tempat dalam kode C; apakah ini seperti fungsi / kelas statis di C # (di mana implementasi dibagikan di seluruh objek)?
Jawaban:
(1) adalah topik yang lebih asing jika Anda seorang pemula, jadi inilah contohnya:
#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();
}
Ini mencetak:
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
Ini berguna untuk kasus-kasus di mana fungsi perlu menjaga beberapa keadaan di antara permintaan, dan Anda tidak ingin menggunakan variabel global. Hati-hati, bagaimanapun, fitur ini harus digunakan dengan sangat hemat - itu membuat kode Anda tidak aman dan sulit untuk dipahami.
(2) Digunakan secara luas sebagai fitur "kontrol akses". Jika Anda memiliki file .c yang mengimplementasikan beberapa fungsi, biasanya hanya memperlihatkan beberapa fungsi "publik" kepada pengguna. Sisa dari fungsinya harus dibuat static
, sehingga pengguna tidak akan dapat mengaksesnya. Ini enkapsulasi, praktik yang baik.
Mengutip Wikipedia :
Dalam bahasa pemrograman C, statis digunakan dengan variabel global dan fungsi untuk mengatur ruang lingkupnya ke file yang berisi. Dalam variabel lokal, statis digunakan untuk menyimpan variabel dalam memori yang dialokasikan secara statis alih-alih memori yang dialokasikan secara otomatis. Sementara bahasa tidak menentukan implementasi dari kedua jenis memori, memori yang dialokasikan secara statis biasanya dicadangkan di segmen data program pada waktu kompilasi, sedangkan memori yang dialokasikan secara otomatis biasanya diimplementasikan sebagai tumpukan panggilan sementara.
Dan untuk menjawab pertanyaan kedua Anda, tidak seperti di C #.
Dalam C ++, bagaimanapun, static
juga digunakan untuk mendefinisikan atribut kelas (dibagi antara semua objek dari kelas yang sama) dan metode. Di C tidak ada kelas, jadi fitur ini tidak relevan.
.c
dan banyak file header, tetapi iblis selalu dalam apa yang tidak khas.
Ada satu lagi penggunaan yang tidak dibahas di sini, dan itu adalah sebagai bagian dari deklarasi tipe array sebagai argumen untuk suatu fungsi:
int someFunction(char arg[static 10])
{
...
}
Dalam konteks ini, ini menetapkan bahwa argumen yang diteruskan ke fungsi ini harus berupa array tipe char
dengan setidaknya 10 elemen di dalamnya. Untuk info lebih lanjut lihat pertanyaan saya di sini .
arg[0]
melalui arg[9]
memiliki nilai-nilai (yang juga menyiratkan bahwa fungsi tidak menerima null pointer). Kompiler dapat memanfaatkan informasi ini entah bagaimana untuk optimasi, dan analisa statis dapat memanfaatkan informasi ini untuk memastikan bahwa fungsi tidak pernah diberi pointer nol (atau jika itu bisa mengatakan, array dengan elemen lebih sedikit daripada yang ditentukan).
static
pada C99. Sudah lebih dari satu setengah dekade, tetapi tidak semua penulis kompiler telah menggunakan semua fitur C99 - jadi C99 secara keseluruhan sebagian besar masih belum diketahui.
int arr[n];
, maka itu adalah VLA (variabel-panjang array) , yang ditambahkan dalam C99. Apakah itu yang kamu maksud?
Jawaban singkat ... itu tergantung.
Variabel lokal yang ditentukan statis tidak kehilangan nilainya di antara panggilan fungsi. Dengan kata lain mereka adalah variabel global, tetapi mencakup fungsi lokal tempat mereka didefinisikan.
Variabel global statis tidak terlihat di luar file C tempat mereka didefinisikan.
Fungsi statis tidak terlihat di luar file C tempat mereka didefinisikan.
private
dalam C, analogi Anda baik: statis membuat hal-hal "pribadi" ke file yang diberikan. Dan file dalam C sering dipetakan ke kelas di C ++.
Contoh lingkup variabel multi-file
Di sini saya menggambarkan bagaimana statis mempengaruhi ruang lingkup definisi fungsi di beberapa file.
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;
}
Kompilasi dan jalankan:
gcc -c a.c -o a.o
gcc -c main.c -o main.o
gcc -o main main.o a.o
Keluaran:
m()
i = 1
si = 1
m()
i = 2
si = 2
a()
i = 3
si = 1
a()
i = 4
si = 2
Penafsiran
si
, satu untuk setiap filei
Seperti biasa, semakin kecil cakupannya, semakin baik, jadi selalu deklarasikan variabel static
jika Anda bisa.
Dalam pemrograman C, file sering digunakan untuk mewakili "kelas", dan static
variabel mewakili anggota statis kelas pribadi.
Apa standar katakan tentang itu
C99 N1256 konsep 6.7.1 " Penentu kelas penyimpanan" mengatakan bahwa itu static
adalah " penentu kelas penyimpanan".
6.2.2 / 3 "Tautan pengidentifikasi" kata static
menyiratkan internal linkage
:
Jika deklarasi pengidentifikasi lingkup file untuk objek atau fungsi berisi statis specifier kelas penyimpanan, pengidentifikasi memiliki tautan internal.
dan 6.2.2 / 2 mengatakan bahwa internal linkage
berperilaku seperti pada contoh kita:
Dalam himpunan unit terjemahan dan pustaka yang merupakan keseluruhan program, setiap deklarasi pengidentifikasi tertentu dengan tautan eksternal menunjukkan objek atau fungsi yang sama. Dalam satu unit terjemahan, setiap deklarasi pengidentifikasi dengan tautan internal menunjukkan objek atau fungsi yang sama.
di mana "unit terjemahan adalah file sumber setelah preprocessing.
Bagaimana GCC mengimplementasikannya untuk ELF (Linux)?
Dengan STB_LOCAL
mengikat.
Jika kami kompilasi:
int i = 0;
static int si = 0;
dan bongkar tabel simbol dengan:
readelf -s main.o
output berisi:
Num: Value Size Type Bind Vis Ndx Name
5: 0000000000000004 4 OBJECT LOCAL DEFAULT 4 si
10: 0000000000000000 4 OBJECT GLOBAL DEFAULT 4 i
jadi pengikatan adalah satu-satunya perbedaan yang signifikan di antara mereka. Value
hanya offset mereka ke dalam .bss
bagian, jadi kami perkirakan berbeda.
STB_LOCAL
didokumentasikan pada spesifikasi ELF di http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html :
STB_LOCAL Simbol lokal tidak terlihat di luar file objek yang berisi definisi mereka. Simbol lokal dengan nama yang sama mungkin ada dalam beberapa file tanpa mengganggu satu sama lain
yang membuatnya menjadi pilihan yang tepat untuk diwakili static
.
Variabel tanpa statis adalah STB_GLOBAL
, dan spesifikasi mengatakan:
Ketika editor tautan menggabungkan beberapa file objek yang dapat dipindahkan, itu tidak memungkinkan beberapa definisi simbol STB_GLOBAL dengan nama yang sama.
yang koheren dengan kesalahan tautan pada beberapa definisi non statis.
Jika kita menghidupkan optimasi dengan -O3
, si
simbol dihapus seluruhnya dari tabel simbol: itu tidak dapat digunakan dari luar. TODO mengapa menyimpan variabel statis di tabel simbol sama sekali ketika tidak ada optimasi? Bisakah mereka digunakan untuk apa saja? Mungkin untuk debugging.
Lihat juga
static
fungsi: https://stackoverflow.com/a/30319812/895245static
dengan extern
, yang artinya "sebaliknya": Bagaimana cara saya menggunakan extern untuk berbagi variabel antara file sumber?C ++ ruang nama anonim
Dalam C ++, Anda mungkin ingin menggunakan ruang nama anonim alih-alih statis, yang mencapai efek yang serupa, tetapi lebih lanjut menyembunyikan definisi tipe: Ruang nama tidak bernama / anonim vs. fungsi statis
Tergantung:
int foo()
{
static int x;
return ++x;
}
Fungsi akan mengembalikan 1, 2, 3, dll --- variabel tidak pada stack.
static int foo()
{
}
Ini berarti bahwa fungsi ini hanya memiliki ruang lingkup di file ini. Jadi ac dan bc dapat memiliki foo()
s yang berbeda , dan foo tidak terkena objek yang dibagikan. Jadi, jika Anda mendefinisikan foo in ac, Anda tidak dapat mengaksesnya dari b.c
atau dari tempat lain.
Di sebagian besar pustaka C semua fungsi "pribadi" bersifat statis dan sebagian besar "publik" tidak.
Orang-orang terus mengatakan bahwa 'statis' dalam C memiliki dua arti. Saya menawarkan cara lain untuk melihatnya yang memberikan makna tunggal:
Alasan yang tampaknya memiliki dua arti adalah bahwa, dalam C, setiap item yang 'statis' dapat diterapkan sudah memiliki salah satu dari dua properti ini , jadi sepertinya penggunaan tertentu itu hanya melibatkan yang lain.
Misalnya, pertimbangkan variabel. Variabel yang dideklarasikan di luar fungsi sudah memiliki kegigihan (di segmen data), jadi menerapkan 'statis' hanya dapat membuatnya tidak terlihat di luar lingkup saat ini (unit kompilasi). Sebaliknya, variabel yang dideklarasikan di dalam fungsi sudah memiliki non-visibilitas di luar lingkup saat ini (fungsi), sehingga penerapan 'statis' hanya dapat membuatnya tetap ada.
Menerapkan 'statis' ke fungsi sama seperti menerapkannya ke variabel global - kode harus persisten (setidaknya dalam bahasa), jadi hanya visibilitas yang dapat diubah.
CATATAN: Komentar ini hanya berlaku untuk C. Dalam C ++, menerapkan metode 'statis' ke kelas benar-benar memberikan arti berbeda pada kata kunci. Demikian pula untuk ekstensi argumen-array C99.
static
memberikan tautan internal ke pengidentifikasi.
Dari Wikipedia:
Dalam bahasa pemrograman C, statis digunakan dengan variabel global dan fungsi untuk mengatur ruang lingkupnya ke file yang berisi. Dalam variabel lokal, statis digunakan untuk menyimpan variabel dalam memori yang dialokasikan secara statis alih-alih memori yang dialokasikan secara otomatis. Sementara bahasa tidak menentukan implementasi dari kedua jenis memori, memori yang dialokasikan secara statis biasanya dicadangkan di segmen data program pada waktu kompilasi, sedangkan memori yang dialokasikan secara otomatis biasanya diimplementasikan sebagai tumpukan panggilan sementara.
static
berarti berbagai hal dalam konteks yang berbeda.
Anda dapat mendeklarasikan variabel statis dalam fungsi C. Variabel ini hanya terlihat dalam fungsinya namun berperilaku seperti global karena hanya diinisialisasi satu kali dan mempertahankan nilainya. Dalam contoh ini, setiap kali Anda memanggilnya foo()
akan mencetak semakin banyak. Variabel statis diinisialisasi hanya sekali.
void foo ()
{
static int i = 0;
printf("%d", i); i++
}
Penggunaan statis lainnya adalah ketika Anda mengimplementasikan suatu fungsi atau variabel global dalam file .c tetapi tidak ingin simbolnya terlihat di luar yang .obj
dihasilkan oleh file tersebut. misalnya
static void foo() { ... }
Jika Anda mendeklarasikan variabel dalam fungsi statis, nilainya tidak akan disimpan di tumpukan panggilan fungsi dan masih akan tersedia saat Anda memanggil fungsi lagi.
Jika Anda mendeklarasikan variabel global statis, cakupannya akan dibatasi dalam file yang Anda nyatakan. Ini sedikit lebih aman daripada global biasa yang dapat dibaca dan dimodifikasi di seluruh program Anda.
Saya benci menjawab pertanyaan lama, tetapi saya rasa tidak ada yang menyebutkan bagaimana K&R menjelaskannya di bagian A4.1 dari "Bahasa Pemrograman C".
Singkatnya, kata statis digunakan dengan dua makna:
static
kata kunci (penekanan besar pada itu digunakan dalam kode sebagai kata kunci) digunakan dengan deklarasi, itu memberi tautan internal objek sehingga hanya dapat digunakan dalam unit terjemahan itu. Tetapi jika kata kunci digunakan dalam suatu fungsi, itu mengubah kelas penyimpanan objek (objek itu hanya akan terlihat dalam fungsi itu). Kebalikan dari statis adalah extern
kata kunci, yang memberikan objek hubungan eksternal.Peter Van Der Linden memberikan dua arti ini dalam "Pemrograman C Ahli":
register
sebuah specifier penyimpanan kelas (C99 6.7.1 specifier penyimpanan kelas). Dan itu lebih dari sekadar petunjuk, misalnya Anda tidak dapat menerapkan alamat-operator &
pada objek dengan kelas penyimpanan register
terlepas dari apakah kompiler mengalokasikan register atau tidak.
Dalam C, statis memiliki dua arti, tergantung pada ruang lingkup penggunaannya. Dalam lingkup global, ketika suatu objek dideklarasikan pada level file, itu berarti objek itu hanya terlihat di dalam file itu.
Pada lingkup lain apa pun itu menyatakan objek yang akan mempertahankan nilainya antara waktu yang berbeda bahwa ruang lingkup tertentu dimasukkan. Misalnya, jika sebuah int dibuat dalam prosedur:
void procedure(void)
{
static int i = 0;
i++;
}
nilai 'i' diinisialisasi ke nol pada panggilan pertama ke prosedur, dan nilai dipertahankan setiap kali prosedur disebut. jika 'i' dicetak maka akan menghasilkan urutan 0, 1, 2, 3, ...
Penting untuk dicatat bahwa variabel statis dalam fungsi dapat diinisialisasi pada entri pertama ke dalam fungsi itu dan tetap ada bahkan setelah panggilan mereka selesai; dalam hal fungsi rekursif, variabel statis hanya diinisialisasi satu kali dan tetap ada di atas semua panggilan rekursif dan bahkan setelah panggilan fungsi selesai.
Jika variabel telah dibuat di luar fungsi, itu berarti bahwa pemrogram hanya dapat menggunakan variabel dalam file sumber yang telah dideklarasikan.
Jika Anda mendeklarasikan ini dalam mytest.c
file:
static int my_variable;
Maka variabel ini hanya bisa dilihat dari file ini. Variabel tidak dapat diekspor ke tempat lain.
Jika Anda mendeklarasikan di dalam fungsi, nilai variabel akan mempertahankan nilainya setiap kali fungsi dipanggil.
Fungsi statis tidak dapat diekspor dari luar file. Jadi dalam sebuah *.c
file, Anda menyembunyikan fungsi dan variabel jika Anda menyatakannya statis.
Variabel statis dalam C memiliki masa pakai program.
Jika didefinisikan dalam suatu fungsi, mereka memiliki cakupan lokal, yaitu mereka hanya dapat diakses di dalam fungsi-fungsi tersebut. Nilai variabel statis dipertahankan antara panggilan fungsi.
Sebagai contoh:
void function()
{
static int var = 1;
var++;
printf("%d", var);
}
int main()
{
function(); // Call 1
function(); // Call 2
}
Dalam program di atas, var
disimpan di segmen data. Masa hidupnya adalah keseluruhan program C.
Setelah panggilan fungsi 1, var
menjadi 2. Setelah panggilan fungsi 2, var
menjadi 3.
Nilai var
tidak dihancurkan antara fungsi panggilan.
Jika var
memiliki antara variabel non-statis dan lokal, itu akan disimpan dalam segmen stack dalam program C. Karena susunan bingkai fungsi dihancurkan setelah fungsi kembali, nilai var
juga dihancurkan.
Variabel statis yang diinisialisasi disimpan dalam segmen data dari program C sedangkan variabel yang tidak diinisialisasi disimpan dalam segmen BSS.
Informasi lain tentang statis: Jika suatu variabel bersifat global dan statis, ia memiliki masa pakai program C, tetapi memiliki cakupan file. Itu hanya terlihat di file itu.
Untuk mencoba ini:
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
Sekarang coba tautkan mereka menggunakan:
gcc -o output file1.o file2.o
Itu akan memberikan kesalahan linker karena x memiliki lingkup file file1.c dan linker tidak akan dapat menyelesaikan referensi ke variabel x yang digunakan dalam file2.c.
Referensi:
static int var = 1;
mengubah nilai kembali ke masing-masing kali
Variabel statis adalah variabel khusus yang dapat Anda gunakan dalam suatu fungsi, dan itu menyimpan data di antara panggilan, dan itu tidak menghapusnya di antara panggilan. Sebagai contoh:
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();
}
}
Hasil:
0, 1, 2, 3, 4, 5, ...
printf("%d, ", count); count++;
dengan `printf ("% d, ", hitung ++) (tidak penting: P).
Ada 2 kasus:
(1) Variabel lokal yang dideklarasikan static
: Dialokasikan dalam segmen data alih-alih tumpukan. Nilainya tetap dipertahankan saat Anda memanggil fungsi lagi.
(2) Variabel atau fungsi global yang dideklarasikan static
: Unit kompilasi luar yang tak terlihat (yaitu simbol lokal dalam tabel simbol selama penautan).
Variabel statis memiliki properti untuk mempertahankan nilainya bahkan setelah mereka berada di luar ruang lingkupnya! Oleh karena itu, variabel statis mempertahankan nilai sebelumnya dalam ruang lingkup sebelumnya dan tidak diinisialisasi lagi dalam ruang lingkup baru.
Lihat ini misalnya - variabel int statis tetap ada dalam memori saat program sedang berjalan. Variabel normal atau otomatis dihancurkan ketika fungsi memanggil tempat variabel itu dinyatakan selesai.
#include<stdio.h>
int fun()
{
static int count = 0;
count++;
return count;
}
int main()
{
printf("%d ", fun());
printf("%d ", fun());
return 0;
}
Ini akan menampilkan: 1 2
Seperti 1 tetap dalam memori seperti yang dinyatakan statis
Variabel statis (seperti variabel global) diinisialisasi sebagai 0 jika tidak diinisialisasi secara eksplisit. Misalnya dalam program di bawah ini, nilai x dicetak sebagai 0, sedangkan nilai y adalah sesuatu yang sampah. Lihat ini untuk lebih jelasnya.
#include <stdio.h>
int main()
{
static int x;
int y;
printf("%d \n %d", x, y);
}
Ini akan menampilkan: 0 [some_garbage_value]
Ini adalah yang utama yang saya temukan yang tidak dijelaskan di atas untuk pemula!
Dalam pemrograman C, static
adalah kata kunci khusus yang mengontrol masa pakai dan visibilitas. Jika kita mendeklarasikan variabel sebagai statis di dalam suatu fungsi maka itu hanya akan terlihat di seluruh fungsi itu. Dalam penggunaan ini, masa pakai variabel statis ini akan mulai ketika fungsi memanggil dan akan dimusnahkan setelah eksekusi fungsi itu. Anda dapat melihat contoh berikut:
#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;
}
Program di atas akan memberi kami Output ini:
First Counter Output = 1
Second Counter Output = 1
Karena begitu kita memanggil fungsi itu akan menginisialisasi count = 0
. Dan sementara kita mengeksekusi counterFunction
itu akan menghancurkan variabel count.