Saat saya mencoba membuat kode ini
inline void f() {}
int main()
{
f();
}
menggunakan baris perintah
gcc -std=c99 -o a a.c
Saya mendapatkan kesalahan penaut (referensi tidak ditentukan ke f
). Kesalahan hilang jika saya menggunakan static inline
atau extern inline
bukan hanya inline
, atau jika saya mengkompilasi dengan -O
(jadi fungsinya sebenarnya sebaris).
Perilaku ini tampaknya didefinisikan dalam paragraf 6.7.4 (6) standar C99:
Jika semua deklarasi cakupan file untuk suatu fungsi dalam unit terjemahan menyertakan
inline
penentu fungsi tanpaextern
, maka definisi dalam unit terjemahan tersebut adalah definisi sebaris. Definisi sebaris tidak memberikan definisi eksternal untuk fungsi tersebut, dan tidak melarang definisi eksternal di unit terjemahan lain. Definisi sebaris memberikan alternatif untuk definisi eksternal, yang dapat digunakan penerjemah untuk mengimplementasikan panggilan apa pun ke fungsi dalam unit terjemahan yang sama. Tidak ditentukan apakah panggilan ke fungsi menggunakan definisi sebaris atau definisi eksternal.
Jika saya memahami semua ini dengan benar, unit kompilasi dengan fungsi yang ditentukan inline
seperti pada contoh di atas hanya mengkompilasi secara konsisten jika ada juga fungsi eksternal dengan nama yang sama, dan saya tidak pernah tahu apakah fungsi saya sendiri atau fungsi eksternal dipanggil.
Bukankah perilaku ini benar-benar gila? Apakah pernah berguna untuk mendefinisikan fungsi inline
tanpa static
atau extern
di C99? Apakah saya melewatkan sesuatu?
Ringkasan jawaban
Tentu saja saya melewatkan sesuatu, dan perilakunya tidak konyol. :)
Seperti yang dijelaskan Nemo , idenya adalah untuk meletakkan definisi fungsi
inline void f() {}
di file header dan hanya deklarasi
extern inline void f();
di file .c yang sesuai. Hanya extern
deklarasi yang memicu pembuatan kode biner yang terlihat secara eksternal. Dan memang tidak ada gunanya inline
dalam file .c - ini hanya berguna di header.
Seperti yang dijelaskan oleh alasan komite C99 yang dikutip dalam jawaban Jonathan , inline
semua tentang pengoptimalan compiler yang memerlukan definisi suatu fungsi agar terlihat di lokasi panggilan. Ini hanya dapat dicapai dengan meletakkan definisi di header, dan tentu saja definisi di header tidak boleh mengeluarkan kode setiap kali dilihat oleh kompiler. Tetapi karena kompilator tidak dipaksa untuk benar-benar menyebariskan suatu fungsi, definisi eksternal harus ada di suatu tempat.
inline
tanpastatic
danextern
, meskipun. Sayangnya, tidak satu pun dari masalah ini tercakup dalam pertanyaan itu.Jawaban:
Sebenarnya jawaban luar biasa ini juga menjawab pertanyaan Anda, saya pikir:
Apa yang dilakukan extern inline?
Idenya adalah bahwa "inline" dapat digunakan dalam file header, dan kemudian "extern inline" dalam file .c. "extern inline" adalah cara Anda menginstruksikan kompilator file objek mana yang harus berisi kode yang dihasilkan (terlihat secara eksternal).
[perbarui, untuk memperinci]
Saya rasa tidak ada gunanya "inline" (tanpa "static" atau "extern") dalam file .c. Namun dalam file header, hal ini masuk akal, dan memerlukan deklarasi "extern inline" yang sesuai di beberapa file .c untuk benar-benar menghasilkan kode yang berdiri sendiri.
sumber
inline void f() {}
di header danextern inline void f();
di file .c? Jadi definisi fungsi sebenarnya berada di header dan file .c berisi deklarasi belaka dalam kasus ini, dalam pembalikan urutan biasa?inline
tanpastatic
atauextern
. Tentu sajastatic inline
baik-baik saja, tetapi pertanyaan dan jawaban ini bukanlah tentang itu.-std=c99
bukan-std=gnu89
.Dari standar (ISO / IEC 9899: 1999) itu sendiri:
Komite C99 menulis Rationale , dan dikatakan:
sumber
> Saya mendapatkan kesalahan penaut (referensi tidak ditentukan kef
)Bekerja di sini: Linux x86-64, GCC 4.1.2. Mungkin ada bug di kompiler Anda; Saya tidak melihat apa pun di paragraf yang dikutip dari standar yang melarang program yang diberikan. Perhatikan penggunaan if daripada iff .Jadi, jika Anda mengetahui perilaku fungsi
f
dan ingin memanggilnya berulang kali, Anda dapat menyalin-tempel definisinya ke dalam modul untuk mencegah pemanggilan fungsi; atau , Anda dapat memberikan definisi yang, untuk tujuan modul saat ini, adalah setara (tetapi melewatkan validasi input, atau pengoptimalan apa pun yang dapat Anda bayangkan). Penulis kompilator, bagaimanapun, memiliki opsi untuk mengoptimalkan ukuran program.sumber