Rumah >pembangunan bahagian belakang >C++ >Fungsi Sebaris dalam C dan C++

Fungsi Sebaris dalam C dan C++

PHPz
PHPzasal
2024-09-09 10:33:46935semak imbas

Inline Functions in C and C++

pengenalan

C++ menambah kata kunci sebaris yang boleh memberi awalan definisi fungsi, seperti:

inline int max_int( int a, int b ) {
    return a > b ? a : b;
}

untuk memberi pengkompil "petunjuk" bahawa program secara keseluruhan mungkin mendapat manfaat dalam prestasi daripada fungsi yang disertakan.

Fungsi yang telah disebari telah dikembangkan kodnya pada setiap titik ia dipanggil dan bukannya melaksanakan mekanisme panggilan fungsi biasa:

  • Menyimpan daftar.
  • Menolak nilai hujah ke dalam tindanan.
  • Melaksanakan arahan panggilan.
  • Fungsi akhirnya melaksanakan arahan ret.
  • Memulihkan daftar.

Untuk fungsi sangat kecil, inlining boleh menghasilkan peningkatan prestasi. Tetapi seperti kebanyakan perkara lain, terdapat pertukaran.

Kata kunci sebaris telah dialihkan kembali ke C99, tetapi dengan keperluan yang sedikit berbeza — lebih kemudian.

Perbezaan dari Makro

Fungsi sebaris adalah seperti (dan bertujuan untuk menggantikan banyak kegunaan) makro seperti fungsi. Secara amnya, ini adalah perkara yang baik kerana fungsi sebaris adalah fungsi dan mempunyai semantik fungsi penuh dan bukannya penggantian teks semata-mata yang dilakukan oleh prapemproses yang tidak memahami sama ada C atau C++.

Makro yang setara dengan fungsi max_int():

#define MAX_INT(A,B)  A > B ? A : B  /* bad implementation */

mempunyai masalah berikut:

  • Argumen yang dikembangkan, cth., MAX(n & 0xFF, 8), boleh mengakibatkan keutamaan operator yang salah.
  • Argumen yang mempunyai kesan sampingan, cth., MAX(n++, 8), boleh mempunyai pelbagai kesan sampingan.
  • Tiada penyemakan jenis hujah pada definisi.
  • Ralat selalunya verbose dan sukar dibaca.

Selain itu, makro:

  • Boleh mengubah suai hujahnya (yang selalunya bukan yang anda mahukan).

Fungsi sebaris tidak mempunyai masalah ini namun boleh menghasilkan manfaat prestasi yang sama. Oleh itu, gunakan fungsi sebaris dan bukannya makro seperti fungsi.

Hanya Petunjuk

Seperti yang dinyatakan, menyatakan sebaris adalah hanya "petunjuk" kepada pengkompil bahawa program secara keseluruhan mungkin mendapat manfaat dalam prestasi daripada fungsi yang diselaraskan. Pengkompil bebas untuk mengabaikan petunjuk.

Kenapa? Kerana terdapat kes apabila ia sama ada idea yang baik atau mustahil. Fungsi sama ada tidak sebaris atau lazimnya tidak sebaris apabila mana-mana satu daripada yang berikut adalah benar:

  • Fungsinya "terlalu besar."
  • Anda memanggil fungsi melalui penuding ke fungsi.
  • Fungsinya adalah rekursif.
  • Fungsi ini mempunyai gelung.

Mungkin ada sebab lain. Semuanya sangat bergantung pada fungsi, hujahnya, pengkompil dan apa sahaja pilihan yang diberikan kepadanya.

Jika pengkompil sama ada tidak boleh atau memilih untuk tidak menyelaraskan fungsi, ia tidak memberi amaran kepada anda bahawa ia tidak melakukannya (secara lalai). Sesetengah penyusun, cth., gcc, mempunyai pilihan -Winline yang akan memberi amaran kepada anda dan memberi anda sebab mengapa fungsi tidak diselaraskan.

Menentukan sebaris adalah serupa dengan kod lama yang menentukan daftar — kedua-duanya hanyalah petunjuk.

Bila (dan Bila Tidak) ke Sebaris

Untuk kebanyakan fungsi, sebahagian besar kos melaksanakan fungsi adalah dalam badan fungsi, bukan dalam mekanisme panggilan fungsi. Oleh itu, untuk membolehkan sesuatu fungsi menjadi calon yang baik untuk sebaris, ia secara amnya mestilah:

  • Cukup kecil sehingga kos mekanisme panggilan fungsi mendominasi.
  • Digunakan di tempat yang prestasi sebenarnya penting, cth., dalam gelung ketat.

Apabila ragu-ragu, profilkan kod anda. Menggunakan sebaris adalah bukan kata kunci ajaib "buat saya lebih pantas". Selain itu, penggunaan sebaris yang berlebihan boleh menyebabkan penyimpangan kod yang juga menjadikan prestasi program anda lebih teruk secara keseluruhan.

Untuk maklumat lanjut, lihat Penyakit sebaris.

Fungsi yang sering menjadi calon yang baik untuk inlining termasuk:

  • "One-liners" seperti "getters" dan "setters."
  • Balut ringkas di sekeliling panggilan ke fungsi lain yang membekalkan nilai khusus untuk hujah atau melakukan hantaran.

Fungsi sebaris yang ideal kedua-duanya meningkatkan prestasi dan mengurangkan saiz kod.

Walau bagaimanapun, satu kaveat untuk mana-mana fungsi sebaris ialah jika takrifannya berubah, ia memerlukan penyusunan semula semua kod yang menggunakannya.

Pengoptimuman Sebaris

Jika fungsi sebaris sebenarnya diselaraskan oleh pengkompil, maka, sebagai tambahan kepada menghapuskan kod untuk mekanisme panggilan fungsi biasa, pengkompil juga mungkin dapat:

  • Eliminate one or more function arguments completely whose values are constants via immediate addressing.
  • Perform better optimizations spanning the code the function is inlined into that it normally couldn’t perform across function boundaries.

Inline Function Definition

In order for the compiler to be able to inline a function, it has to be able to “see” its definition (not just its declaration) in every .c or .cpp file it’s used in just like a macro. Hence, an inline function must be defined in a header file.

Normally, a function, like everything else, must have exactly one definition by adhering to the one definition rule (ODR). However, since the definition of an inline function is “seen” in multiple .c or .cpp files, the ODR is suspended for that function.

It is possible to have different definitions for inline functions having the same name, but this results in undefined behavior since the compiler has no way to check that every definition is the same.

To inline a function in C++, all you need do is prefix the function definition with inline — that’s it. The compiler and/or linker will automatically discard all but one definition from the final executable file for you.

However, to inline a function in C, you additionally must explicitly tell the compiler into what .o file to put the one definition in the event the compiler is either unable or unwilling to inline a function via extern inline.

For example, in exactly one .c file, you would declare a function like:

// util.c
extern inline int max_int( int, int );

That tells the compiler to “put the one definition for max_int() into util.o.”

Alternatively in C, you can instead declare an inline function static also:

static inline int max_int( int a, int b ) {
    return a > b ? a : b;
}

If you do this, then:

  • You do not have to declare a function extern inline anywhere.
  • However, if the compiler doesn’t inline a function, it will generate a definition in every .c file it’s included into again leading to code bloat.
  • If the function has any static local variables, every definition will have distinct copies (that may or may not be what you want).

Conclusion

Inline functions, if used judiciously, can yield performance gains. Generally, only very small functions are good candidates for inlining.

Starting in C++11, inline functions can alternatively be declared constexpr, but that’s a story for another time.

References

  • Linux kernel coding style, §15 The inline disease.
  • Myth and reality about inline in C99.
  • The Annotated C++ Reference Manual, Margaret A. Ellis & Bjarne Stroustrup, Addison-Wesley, 1990, ISBN 0-201-51459-1, §7.1.2 Function Specifiers, pp. 99–105.

Atas ialah kandungan terperinci Fungsi Sebaris dalam C dan C++. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn