Apa perbedaan antara fungsi "statis" dan "sebaris statis"?

123

IMO keduanya membuat fungsinya hanya memiliki cakupan unit terjemahan.

Apa perbedaan antara fungsi "statis" dan "sebaris statis"?

Kenapa harus inlinedi taruh di file header, bukan di .cfile?

new_perl
sumber

Jawaban:

109

inlinemenginstruksikan kompilator untuk mencoba menyematkan konten fungsi ke dalam kode panggilan alih-alih menjalankan panggilan yang sebenarnya.

Untuk fungsi kecil yang sering dipanggil dapat membuat perbedaan performa yang besar.

Namun, ini hanya sebuah "petunjuk", dan kompilator mungkin mengabaikannya, dan sebagian besar kompiler akan mencoba "sebaris" bahkan ketika kata kunci tidak digunakan, sebagai bagian dari pengoptimalan, jika memungkinkan.

sebagai contoh:

static int Inc(int i) {return i+1};
.... // some code
int i;
.... // some more code
for (i=0; i<999999; i = Inc(i)) {/*do something here*/};

Loop ketat ini akan melakukan pemanggilan fungsi pada setiap iterasi, dan konten fungsi sebenarnya jauh lebih kecil daripada kode yang perlu dimasukkan oleh compiler untuk melakukan panggilan. inlinepada dasarnya akan menginstruksikan kompiler untuk mengubah kode di atas menjadi setara dengan:

 int i;
 ....
 for (i=0; i<999999; i = i+1) { /* do something here */};

Melewati pemanggilan dan pengembalian fungsi yang sebenarnya

Jelas ini adalah contoh untuk menunjukkan intinya, bukan potongan kode yang sebenarnya.

staticmengacu pada ruang lingkup. Dalam C itu berarti bahwa fungsi / variabel hanya dapat digunakan dalam unit terjemahan yang sama.

littleadv
sumber
4
Tidak, staticmengacu pada ruang lingkup. Dalam C itu berarti bahwa fungsi / variabel hanya dapat digunakan dalam unit terjemahan yang sama.
littleadv
8
Penting juga untuk dicatat bahwa kode yang dideklarasikan sebagai inline termasuk dalam header, sedangkan kode sumber normal (non-template) tidak dapat masuk ke dalam header tanpa menyebabkan beberapa kesalahan redefinisi. Jadi, bahkan saat mendeklarasikan sesuatu sebaris, bahkan jika compiler memilih untuk tidak menyebariskannya, masih ada perilaku menghindari definisi ganda dengan mandat standar yang muncul.
VoidStar
13
@VoidStar Sebenarnya static(dengan atau tanpa inline) bisa di header dengan baik, tidak ada alasan kenapa tidak. Template untuk C ++, pertanyaan ini tentang C.
littleadv
2
@littleadv: alasan utama untuk meletakkan definisi fungsi dalam file header adalah membuatnya tidak dapat ditata, jadi menandainya secara eksplisit inlineadalah gaya yang baik, imo
Christoph
9
Sebenarnya inlinetidak menginstruksikan kompilator untuk melakukan upaya apa pun dalam menyebariskan. Ini hanya memungkinkan programmer untuk memasukkan badan fungsi dalam beberapa unit terjemahan tanpa pelanggaran ODR. Efek samping dari hal ini adalah memungkinkan kompilator, ketika ia akan menyebariskan fungsi, untuk benar-benar melakukan ini.
Ruslan
96

Secara default, definisi sebaris hanya valid di unit terjemahan saat ini.

Jika kelas penyimpanannya adalah extern, pengidentifikasi memiliki hubungan eksternal dan definisi sebaris juga memberikan definisi eksternal.

Jika kelas penyimpanannya adalah static, pengenal memiliki tautan internal dan definisi sebaris tidak terlihat di unit terjemahan lain.

Jika kelas penyimpanan tidak ditentukan, definisi sebaris hanya terlihat di unit terjemahan saat ini, tetapi pengenal masih memiliki tautan eksternal dan definisi eksternal harus disediakan di unit terjemahan yang berbeda. Kompilator bebas menggunakan definisi inline atau eksternal jika fungsi dipanggil dalam unit terjemahan saat ini.

Karena kompiler bebas untuk menyebariskan (dan tidak menyebariskan) fungsi apa pun yang definisinya terlihat di unit terjemahan saat ini (dan, berkat pengoptimalan waktu tautan, bahkan di unit terjemahan yang berbeda, meskipun standar C tidak benar-benar memperhitungkan that), untuk sebagian besar tujuan praktis, tidak ada perbedaan antara definisi staticdan static inlinefungsi.

The inlinespecifier (seperti registerkelas penyimpanan) hanya sedikit compiler, dan compiler gratis untuk benar-benar mengabaikannya. Kompiler non-pengoptimalan yang sesuai standar hanya perlu menghormati efek sampingnya, dan pengoptimal kompiler akan melakukan pengoptimalan ini dengan atau tanpa petunjuk eksplisit.

inlinedan registerbukan tidak berguna, meskipun, karena mereka menginstruksikan compiler untuk melempar kesalahan ketika programmer menulis kode yang akan membuat pengoptimalan menjadi tidak mungkin: inlineDefinisi eksternal tidak dapat merujuk pengenal dengan tautan internal (karena ini tidak akan tersedia di unit terjemahan yang berbeda) atau tentukan variabel lokal yang dapat dimodifikasi dengan durasi penyimpanan statis (karena ini tidak akan berbagi status di seluruh unit terjemahan), dan Anda tidak dapat mengambil alamat registervariabel yang memenuhi syarat.

Secara pribadi, saya menggunakan konvensi untuk menandai staticdefinisi fungsi di dalam header juga inline, karena alasan utama untuk meletakkan definisi fungsi dalam file header adalah membuatnya tidak dapat dibariskan.

Secara umum, saya hanya menggunakan static inlinestatic const definisi fungsi dan objek selain externdeklarasi di dalam header.

Saya tidak pernah menulis inlinefungsi dengan kelas penyimpanan yang berbeda dari static.

Christoph
sumber
8
Ini jawaban yang benar. Setiap jawaban yang dibicarakan inlineseolah-olah benar-benar diterapkan pada sebaris adalah menyesatkan dan bisa dibilang salah. Tidak ada kompiler modern yang menggunakannya sebagai petunjuk untuk menyebariskan atau memerlukannya untuk mengaktifkan sebaris suatu fungsi.
Tyg13
1
suara positif untuk "gunakan konvensi untuk menandai definisi fungsi statis dalam tajuk sebaris".
John Z. Li
Saya membaca seluruh jawaban Anda dan saya masih tidak mengerti perbedaan semantik antara staticdan static inline. Keduanya membuat definisi tersebut tidak terlihat oleh unit terjemahan lain. Jadi apa alasan yang masuk akal untuk menulis static inlinedaripada menulis static?
pengguna541686
21

Dari pengalaman saya dengan GCC, saya mengetahuinya staticdan static inlineberbeda dalam hal bagaimana kompilator mengeluarkan peringatan tentang fungsi yang tidak digunakan. Lebih tepatnya ketika Anda mendeklarasikan staticfungsi dan itu tidak digunakan dalam unit terjemahan saat ini maka compiler menghasilkan peringatan tentang fungsi yang tidak digunakan, tetapi Anda dapat menghambat peringatan itu dengan mengubahnya menjadi static inline.

Jadi saya cenderung berpikir bahwa staticharus digunakan dalam unit terjemahan dan manfaat dari kompilator cek ekstra tidak untuk menemukan fungsi yang tidak digunakan. Dan static inlinesebaiknya digunakan di file header untuk menyediakan fungsi yang bisa di-line (karena tidak adanya linkage eksternal) tanpa mengeluarkan peringatan.

Sayangnya saya tidak dapat menemukan bukti untuk logika itu. Bahkan dari dokumentasi GCC saya tidak dapat menyimpulkan bahwa inlinemenghalangi peringatan fungsi yang tidak digunakan. Saya akan menghargai jika seseorang akan membagikan tautan ke deskripsi itu.

ony
sumber
1
Mmm, masih punya warning: unused function 'function' [clang-diagnostic-unused-function]untuk static inlinefungsi ketika membangun dengan clang-tidy(v8.0.1), yang digunakan di unit lain terjemahan. Tapi yang pasti, ini adalah salah satu penjelasan dan alasan terbaik untuk menggabungkan static& inline!
DrumM
6

Di C, staticberarti fungsi atau variabel yang Anda tentukan hanya dapat digunakan di file ini (yaitu unit kompilasi)

Jadi, static inlineartinya fungsi inline yang hanya bisa digunakan di file ini.

EDIT:

Unit kompilasi haruslah The Translation Unit

shengy
sumber
2
Atau dengan kata-kata indah: ia memiliki hubungan internal.
K-ballo
@AlokSave: Apakah ada perbedaan antara unit kompilasi dan unit terjemahan ? Jika ya, mana yang lebih sesuai dalam konteks bahasa C ++?
legends2k
Saya percaya the compile unitada sesuatu yang saya tulis karena kesalahan, tidak ada hal seperti itu, terminologi sebenarnya adalahtranslation unit
shengy
Jawaban Anda tidak lengkap karena kebanyakan digunakan dalam file header, di seluruh unit terjemahan.
DrumM
5

Satu perbedaan yang bukan pada level bahasa tetapi pada level implementasi populer: versi gcc tertentu akan menghapus static inlinefungsi yang tidak direferensikan dari keluaran secara default, tetapi akan mempertahankan staticfungsi biasa meskipun tidak direferensikan. Saya tidak yakin versi mana ini berlaku untuk, tetapi dari sudut pandang praktis itu berarti mungkin ide yang baik untuk selalu digunakan inlineuntuk staticfungsi di header.

R .. GitHub BERHENTI ICE BANTUAN
sumber
Bagaimana dengan menggunakan inlinedefinisi? Apakah Anda juga menyiratkan tidak menggunakannya untuk externfungsi?
new_perl
Apakah ini masih berlaku dengan versi GCC terbaru? Jawaban Anda akan jauh lebih menarik jika Anda memberi contoh dan mencantumkan versi GCC mana yang melakukannya.
Z boson
@ Zboson: Saya tidak memiliki informasi tersebut dan tidak punya waktu untuk menyiapkan dan menguji banyak versi gcc saat ini, tetapi saya setuju bahwa informasi itu berguna untuk dimiliki. Anda mungkin dapat menemukan saat gcc pertama kali mulai mengoptimalkan fungsi / objek statis yang tidak digunakan dengan melihat riwayat attribute((used))dan penggunaannya untuk memungkinkan asm mereferensikan staticfungsi dan data yang tidak direferensikan .
R .. GitHub STOP HELPING ICE