Pertanyaan Apa arti "statis" dalam C?


Saya telah melihat kata itu static digunakan di tempat yang berbeda dalam kode C; apakah ini seperti fungsi / kelas statis di C # (di mana implementasi dibagi di seluruh objek)?


854
2018-02-21 06:47


asal


Jawaban:


  1. Sebuah variabel statis di dalam suatu fungsi menyimpan nilainya di antara invokasi.
  2. Sebuah variabel global statis atau fungsi "terlihat" hanya dalam file yang dideklarasikan

(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();
}

Cetakan ini:

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 suatu fungsi perlu menjaga beberapa keadaan antara invokasi, dan Anda tidak ingin menggunakan variabel global. Waspadalah, bagaimanapun, fitur ini harus digunakan dengan sangat hemat - itu membuat kode Anda tidak aman-thread dan lebih sulit untuk dipahami.

(2) Digunakan secara luas sebagai fitur "kontrol akses". Jika Anda memiliki file .c menerapkan beberapa fungsi, biasanya hanya memperlihatkan beberapa fungsi "publik" kepada pengguna. Sisa dari fungsinya harus dibuat static, sehingga pengguna tidak dapat mengaksesnya. Ini adalah enkapsulasi, praktik yang baik.

Mengutip Wikipedia:

Dalam bahasa pemrograman C, statis   digunakan dengan variabel global dan   fungsi untuk mengatur ruang lingkup mereka ke   berisi file. Dalam variabel lokal,   statis digunakan untuk menyimpan variabel   dalam memori yang dialokasikan secara statis   bukannya dialokasikan secara otomatis   ingatan. Sedangkan bahasa tidak   mendikte pelaksanaan keduanya   jenis memori, dialokasikan secara statis   memori biasanya disimpan dalam data   segmen program di kompilasi   waktu, sementara secara otomatis   memori yang dialokasikan biasanya   diimplementasikan sebagai panggilan stack sementara.

Lihat sini dan sini untuk lebih jelasnya.

Dan untuk menjawab pertanyaan kedua Anda, itu tidak seperti di C #.

Namun, dalam C ++, 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.


1221
2018-02-21 06:51



Ada satu lagi penggunaan yang tidak dibahas di sini, dan itu adalah sebagai bagian dari deklarasi tipe larik sebagai argumen untuk fungsi:

int someFunction(char arg[static 10])
{
    ...
}

Dalam konteks ini, ini menentukan bahwa argumen yang dilewatkan ke fungsi ini harus berupa array tipe char dengan setidaknya 10 elemen di dalamnya. Untuk info lebih lanjut lihat pertanyaan saya sini.


188
2018-05-01 07:13



Jawaban singkat ... tergantung.

  1. Variabel lokal yang ditentukan secara statis tidak kehilangan nilainya di antara pemanggilan fungsi. Dengan kata lain, mereka adalah variabel global, tetapi disesuaikan dengan fungsi lokal yang ditentukan.

  2. Variabel global statis tidak terlihat di luar file C yang ditentukan.

  3. Fungsi statis tidak terlihat di luar file C yang ditentukan.


140
2018-02-21 06:56



Contoh lingkup variabel multi-file

a.c:

#include <stdio.h>

/*
Undefined behavior: already defined in main.
Binutils 2.24 gives an error and refuses to link.
https://stackoverflow.com/questions/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:

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

Interpretasi

  • ada dua variabel terpisah untuk si, satu untuk setiap file
  • ada satu variabel bersama untuk i

Seperti biasa, semakin kecil ruang lingkup, semakin baik, sehingga selalu mendeklarasikan variabel staticjika kamu bisa.

Dalam pemrograman C, file sering digunakan untuk mewakili "kelas", dan static variabel mewakili anggota statis privat dari kelas.

Apa yang dikatakan standar tentang itu

C99 N1256 draft 6.7.1 "Specifier penyimpanan-kelas" mengatakan itu static adalah "penentu kelas penyimpanan".

6.2.2 / 3 "Tautan pengidentifikasi" berkata static menyiratkan internal linkage:

Jika deklarasi pengidentifikasi cakupan file untuk suatu objek atau fungsi berisi penentu kelas penyimpanan statis, pengidentifikasi memiliki hubungan internal.

dan 6.2.2 / 2 mengatakan itu internal linkage berperilaku seperti dalam contoh kita:

Dalam set unit terjemahan dan pustaka yang membentuk keseluruhan program, setiap deklarasi dari pengidentifikasi tertentu dengan hubungan eksternal menunjukkan objek atau fungsi yang sama. Dalam satu unit terjemahan, setiap deklarasi identifier dengan hubungan 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 mengkompilasi:

int i = 0;
static int si = 0;

dan membongkar 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 mengharapkannya 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 di beberapa file tanpa mengganggu satu sama lain

yang menjadikannya pilihan yang sempurna untuk mewakili static.

Variabel tanpa statis STB_GLOBAL, dan speknya 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 meningkatkan optimasi dengan -O3, yang si Simbol dihapus sepenuhnya dari tabel simbol: itu tidak dapat digunakan dari luar lagian. TODO mengapa menyimpan variabel statis pada tabel simbol sama sekali ketika tidak ada pengoptimalan? Bisakah mereka digunakan untuk apa saja? Mungkin untuk debugging.

Lihat juga

Cobalah sendiri

Contoh di github untuk kamu mainkan.


45
2018-01-15 13:41



Tergantung:

int foo()
{
   static int x;
   return ++x;
}

Fungsi akan mengembalikan 1, 2, 3, dll. --- variabelnya tidak ada dalam tumpukan.

a.c:

static int foo()
{
}

Ini berarti bahwa fungsi ini hanya memiliki cakupan dalam file ini. Jadi a.c dan b.c bisa berbeda foo()s, dan foo tidak terkena objek bersama. Jadi jika Anda mendefinisikan foo di a.c Anda tidak dapat mengaksesnya b.c atau dari tempat lain.

Di sebagian besar perpustakaan C semua fungsi "pribadi" bersifat statis dan sebagian besar "publik" tidak.


32
2018-02-21 06:57



Orang-orang terus mengatakan bahwa 'statis' dalam bahasa C memiliki dua arti. Saya menawarkan cara lain untuk melihatnya yang memberinya arti tunggal:

  • Menerapkan 'statis' ke item memaksa item itu memiliki dua properti: (a) Tidak terlihat di luar lingkup saat ini; (B) itu terus-menerus.

Alasannya tampaknya memiliki dua makna adalah bahwa, dalam C, setiap item yang 'statis' dapat diterapkan sudah memiliki salah satu dari dua properti ini, sehingga tampaknya seolah-olah penggunaan khusus itu hanya melibatkan yang lain.

Misalnya, pertimbangkan variabel. Variabel yang dideklarasikan di luar fungsi sudah memiliki persistensi (dalam segmen data), jadi menerapkan 'statis' hanya dapat membuat mereka tidak terlihat di luar lingkup saat ini (unit kompilasi). Sebaliknya, variabel yang dideklarasikan di dalam fungsi sudah tidak terlihat di luar lingkup saat ini (fungsi), jadi menerapkan 'statis' hanya dapat membuat mereka tetap.

Menerapkan 'statis' ke fungsi seperti menerapkannya ke variabel global - kode selalu persisten (setidaknya dalam bahasa), sehingga hanya visibilitas yang dapat diubah.

CATATAN: Komentar ini hanya berlaku untuk C. Dalam C ++, menerapkan 'statis' ke metode kelas benar-benar memberikan kata kunci arti yang berbeda. Demikian pula untuk ekstensi array-argumen C99.


18
2018-04-27 13:47



static berarti hal yang berbeda dalam konteks yang berbeda.

  1. Anda dapat mendeklarasikan variabel statis dalam fungsi C. Variabel ini hanya terlihat dalam fungsi namun berperilaku seperti global karena hanya diinisialisasi sekali dan mempertahankan nilainya. Dalam contoh ini, setiap kali Anda menelepon foo() itu akan mencetak peningkatan angka. Variabel statis diinisialisasi hanya sekali.

    void foo ()
    {
    static int i = 0;
    printf("%d", i); i++
    }
    
  2. Penggunaan lain dari statis adalah ketika Anda mengimplementasikan fungsi atau variabel global dalam file .c tetapi tidak ingin simbolnya terlihat di luar .obj dihasilkan oleh file. misalnya

    static void foo() { ... }
    

12
2018-02-21 06:55



Dari Wikipedia:

Dalam bahasa pemrograman C, statis digunakan dengan variabel global dan fungsi untuk mengatur ruang lingkup mereka ke file yang berisi. Dalam variabel lokal, statis digunakan untuk menyimpan variabel dalam memori yang dialokasikan secara statis daripada memori yang dialokasikan secara otomatis. Sementara bahasa tidak menentukan pelaksanaan kedua jenis memori, memori yang dialokasikan secara statis biasanya dicadangkan di segmen data dari program pada waktu kompilasi, sementara memori yang dialokasikan secara otomatis biasanya diimplementasikan sebagai tumpukan panggilan sementara.


11
2018-02-21 06:52



Saya tidak suka menjawab pertanyaan lama, tetapi saya tidak berpikir ada yang menyebutkan bagaimana K & R menjelaskannya di bagian A4.1 dari "The C Programming Language".

Singkatnya, kata statis digunakan dengan dua makna:

  1. Statis adalah salah satu dari dua kelas penyimpanan (yang lainnya otomatis). Objek statis menyimpan nilainya di antara invokasi. Objek yang dideklarasikan di luar semua blok selalu statis dan tidak dapat dibuat otomatis.
  2. Tapi, saat itu static  kata kunci (penekanan besar pada itu digunakan dalam kode sebagai kata kunci) digunakan dengan deklarasi, memberikan hubungan internal objek sehingga hanya dapat digunakan dalam unit terjemahan itu. Tetapi jika kata kunci digunakan dalam fungsi, itu mengubah kelas penyimpanan objek (objek hanya akan terlihat dalam fungsi itu). Kebalikan dari statis adalah extern kata kunci, yang memberikan tautan eksternal objek.

Peter Van Der Linden memberikan dua arti ini dalam "Expert C Programming":

  • Di dalam fungsi, mempertahankan nilainya di antara panggilan.
  • Di tingkat fungsi, hanya terlihat di file ini.

6
2018-03-30 23:49



Jika Anda mendeklarasikan variabel dalam fungsi statis, nilainya tidak akan disimpan pada tumpukan panggilan fungsi dan akan tetap tersedia saat Anda memanggil fungsi itu lagi.

Jika Anda menyatakan variabel global statis, ruang lingkupnya akan dibatasi ke dalam file di mana Anda mendeklarasikannya. Ini sedikit lebih aman daripada global biasa yang dapat dibaca dan dimodifikasi di seluruh program Anda.


5
2018-02-21 06:52



Dalam C, statis memiliki dua arti, tergantung pada ruang lingkup penggunaannya. Dalam lingkup global, ketika suatu objek dideklarasikan pada tingkat file, itu berarti bahwa objek itu hanya terlihat dalam file itu.

Pada setiap ruang lingkup lain menyatakan objek yang akan mempertahankan nilainya antara waktu yang berbeda bahwa ruang lingkup tertentu dimasukkan. Misalnya, jika int dihapus dalam prosedur:

void procedure(void)
{
   static int i = 0;

   i++;
}

nilai 'i' diinisialisasi ke nol pada panggilan pertama ke prosedur, dan nilainya dipertahankan setiap kali prosedur dipanggil. jika 'i' dicetak akan menghasilkan urutan 0, 1, 2, 3, ...


5
2018-02-21 07:20