Apa gunanya membuat fungsi statis di C?
Apa gunanya membuat fungsi statis di C?
Jawaban:
Membuat fungsi static
menyembunyikannya dari unit terjemahan lain, yang membantu menyediakan enkapsulasi .
helper_file.c
int f1(int); /* prototype */
static int f2(int); /* prototype */
int f1(int foo) {
return f2(foo); /* ok, f2 is in the same translation unit */
/* (basically same .c file) as f1 */
}
int f2(int foo) {
return 42 + foo;
}
main.c :
int f1(int); /* prototype */
int f2(int); /* prototype */
int main(void) {
f1(10); /* ok, f1 is visible to the linker */
f2(12); /* nope, f2 is not visible to the linker */
return 0;
}
#include <helper_file.c>
? Saya pikir itu akan menjadikannya unit terjemahan tunggal ...
gcc -std=c99 -pedantic -Wall -Wextra main.c helper_file.c
. Prototipe untuk fungsi hadir di kedua file sumber (tidak perlu untuk file header). Tautan akan menyelesaikan fungsi.
pmg tepat tentang enkapsulasi; selain menyembunyikan fungsi dari unit terjemahan lain (atau lebih tepatnya, karena itu), membuat fungsi static
juga dapat memberi manfaat kinerja dengan adanya optimisasi kompiler.
Karena suatu static
fungsi tidak dapat dipanggil dari mana saja di luar unit terjemahan saat ini (kecuali jika kode membawa pointer ke alamatnya), kompiler mengontrol semua titik panggilan ke dalamnya.
Ini berarti bahwa bebas untuk menggunakan ABI non-standar, sebaris sepenuhnya, atau melakukan sejumlah optimasi lain yang mungkin tidak dapat dilakukan untuk fungsi dengan tautan eksternal.
static
fungsi keluar dari unit terjemahan saat ini, maka fungsi tersebut dapat langsung dipanggil dari unit terjemahan lainnya.
Itu static
kunci dalam C digunakan dalam file yang dikompilasi (.c sebagai lawan dari .h) sehingga fungsi hanya ada di file itu.
Biasanya, ketika Anda membuat suatu fungsi, kompiler menghasilkan cruft yang bisa digunakan oleh linker, yah, menautkan pemanggilan fungsi ke fungsi itu. Jika Anda menggunakan kata kunci statis, fungsi lain dalam file yang sama dapat memanggil fungsi ini (karena dapat dilakukan tanpa beralih ke linker), sementara linker tidak memiliki informasi membiarkan file lain mengakses fungsi.
Melihat posting di atas saya ingin menunjukkan satu detail.
Misalkan file utama kami ("main.c") terlihat seperti ini:
#include "header.h"
int main(void) {
FunctionInHeader();
}
Sekarang pertimbangkan tiga kasus:
Kasus 1: File header kami ("header.h") terlihat seperti ini:
#include <stdio.h>
static void FunctionInHeader();
void FunctionInHeader() {
printf("Calling function inside header\n");
}
Kemudian perintah berikut di linux:
gcc main.c header.h -o main
akan berhasil ! Mengikuti itu jika satu berjalan
./main
Outputnya adalah
Fungsi panggilan di dalam header
Apa fungsi statis yang harus dicetak.
Kasus 2: File header kami ("header.h") terlihat seperti ini:
static void FunctionInHeader();
dan kami juga memiliki satu file lagi "header.c", yang terlihat seperti ini:
#include <stdio.h>
#include "header.h"
void FunctionInHeader() {
printf("Calling function inside header\n");
}
Lalu perintah berikut
gcc main.c header.h header.c -o main
akan memberikan kesalahan.
Kasus 3:
Mirip dengan kasus 2, kecuali bahwa sekarang file header kami ("header.h") adalah:
void FunctionInHeader(); // keyword static removed
Maka perintah yang sama seperti dalam kasus 2 akan berhasil, dan eksekusi selanjutnya ./main akan memberikan hasil yang diharapkan.
Jadi dari tes ini (dijalankan pada mesin Acer x86, Ubuntu OS) saya membuat asumsi itu
kata kunci statis mencegah fungsi dipanggil dalam file * .c lain daripada yang didefinisikan.
Koreksi saya jika saya salah.
Pemrogram C menggunakan atribut statis untuk menyembunyikan deklarasi variabel dan fungsi di dalam modul, seperti halnya Anda akan menggunakan deklarasi publik dan pribadi di Java dan C ++. File sumber C memainkan peran modul. Setiap variabel global atau fungsi yang dideklarasikan dengan atribut statis adalah pribadi untuk modul itu. Demikian pula, setiap variabel atau fungsi global yang dideklarasikan tanpa atribut statis bersifat publik dan dapat diakses oleh modul lainnya. Merupakan praktik pemrograman yang baik untuk melindungi variabel dan fungsi Anda dengan atribut statis sedapat mungkin.
jawaban pmg sangat meyakinkan. Jika Anda ingin tahu bagaimana deklarasi statis bekerja pada level objek maka info di bawah ini bisa menarik bagi Anda. Saya menggunakan kembali program yang sama yang ditulis oleh pmg dan mengompilasinya menjadi file .so (shared object)
Konten berikut adalah setelah membuang file .so ke sesuatu yang dapat dibaca manusia
0000000000000675 f1 : alamat fungsi f1
000000000000068c f2 : alamat fungsi f2 (staticc)
perhatikan perbedaan dalam alamat fungsi, itu berarti sesuatu. Untuk fungsi yang dideklarasikan dengan alamat yang berbeda, ia dapat dengan baik menandakan bahwa f2 tinggal sangat jauh atau dalam segmen berbeda dari file objek.
Linker menggunakan sesuatu yang disebut PLT (Tabel tautan prosedur) dan GOT (tabel offset global) untuk memahami simbol yang mereka miliki aksesnya.
Untuk saat ini berpikir bahwa GOT dan PLT secara ajaib mengikat semua alamat dan bagian dinamis menyimpan informasi dari semua fungsi ini yang dapat dilihat oleh tautan.
Setelah membuang bagian dinamis dari file .so kita mendapatkan banyak entri tetapi hanya tertarik pada fungsi f1 dan f2 .
Bagian dinamis menyimpan entri hanya untuk fungsi f1 di alamat 0000000000000675 dan bukan untuk f2 !
Num: Nilai Ukuran Tipe Bind Vis Ndx Name
9: 0000000000000675 23 FUNC GLOBAL DEFAULT 11 f1
Dan itu dia! Dari sini jelas bahwa penghubung akan gagal menemukan fungsi f2 karena tidak ada di bagian dinamis dari file .so.
Ketika ada kebutuhan untuk membatasi akses ke beberapa fungsi, kami akan menggunakan kata kunci statis sambil mendefinisikan dan mendeklarasikan suatu fungsi.
/* file ab.c */
static void function1(void)
{
puts("function1 called");
}
And store the following code in another file ab1.c
/* file ab1.c */
int main(void)
{
function1();
getchar();
return 0;
}
/* in this code, we'll get a "Undefined reference to function1".Because function 1 is declared static in file ab.c and can't be used in ab1.c */