Keyword inline memberi tahu compiler bahwa suatu fungsi sebaiknya di-inline—disisipkan langsung ke pemanggilnya daripada dipanggil via instruksi call. Tujuannya adalah menghindari overhead pemanggilan fungsi (passing argumen, stack frame, return address) untuk fungsi yang sangat pendek. Inline adalah saran, bukan perintah—compiler bebas mengabaikannya jika menilai inlining tidak menguntungkan. Pada chapter ini kita akan mempraktikkan static inline di header (pola paling aman), inline non-static yang memerlukan definisi extern terpisah, dan perbandingan dengan macro berparameter.
Mekanisme Inline #
Saat compiler melihat fungsi static inline int kuadrat(int x) { return x * x; } dan menemui pemanggilan kuadrat(5), compiler dapat menyisipkan kode 5 * 5 langsung ke tempat pemanggilan—menghindari instruksi call kuadrat dan return. Hasilnya adalah kode yang lebih cepat (tanpa overhead pemanggilan) tetapi biasanya lebih besar (kode fungsi diduplikasi di setiap pemanggilan). Karena itu inline paling cocok untuk fungsi pendek—beberapa baris saja.
Inline juga memungkinkan optimasi lebih lanjut. Compiler dapat melakukan constant folding (mis. kuadrat(5) langsung dihitung saat kompilasi menjadi 25) atau propagasi tipe yang lebih akurat. Pada fungsi yang lebih panjang, inlining dapat justru memperlambat program karena instruction cache menjadi tidak efektif—compiler modern menggunakan heuristic untuk memilih fungsi mana yang sebaiknya di-inline.
Pola static inline di Header #
Pola paling aman dan paling umum: definisikan fungsi sebagai static inline di header. Keyword static memberikan internal linkage—setiap translation unit yang meng-include header mendapatkan salinan fungsi sendiri. Keyword inline memberi tahu compiler bahwa fungsi boleh di-inline. Kombinasi ini menghindari multiple definition karena setiap salinan adalah simbol lokal.
File math_inline.h:
#ifndef MATH_INLINE_H
#define MATH_INLINE_H
/* static inline: aman di header, tidak menyebabkan multiple definition */
static inline int kuadrat(int x) {
return x * x;
}
static inline int maks(int a, int b) {
return (a > b) ? a : b;
}
static inline double rata_rata(int a, int b) {
return (a + b) / 2.0;
}
#endifFile main.c:
#include <stdio.h>
#include "math_inline.h"
int main(void) {
int a = 5, b = 7;
printf("kuadrat(%d) = %d\n", a, kuadrat(a));
printf("maks(%d, %d) = %d\n", a, b, maks(a, b));
printf("rata_rata(%d, %d) = %.2f\n", a, b, rata_rata(a, b));
return 0;
}Kompilasi dan jalankan:
gcc -std=c11 -Wall -Wextra -I. -o app main.c && ./appOutput yang Dihasilkan:
kuadrat(5) = 25
maks(5, 7) = 7
rata_rata(5, 7) = 6.00Mari kita telaah baris-baris kunci di atas:
- Pada
math_inline.hbaris 6 (static inline int kuadrat(int x) { return x * x; }): definisi fungsistatic inline. Keywordstaticmemberi internal linkage sehingga fungsi tidak terlihat dari object file lain (tidak muncul sebagai simbolTdinm). Keywordinlineadalah saran ke compiler untuk menyisipkan kode fungsi langsung ke pemanggil. - Pada
math_inline.hbaris 10 (static inline int maks(int a, int b)): implementasi dengan operator ternary?:. Fungsi sangat pendek (satu ekspresi) sehingga ideal untuk inline. - Pada
math_inline.hbaris 14 (static inline double rata_rata(int a, int b)): perhatikan ekspresi(a + b) / 2.0menggunakan2.0(bukan2) untuk memaksa pembagian floating-point. Jika kita menulis(a + b) / 2, hasilnya adalah pembagian integer yang akan terpotong. - Pada
main.cbaris 6 (printf("kuadrat(%d) = %d\n", a, kuadrat(a));): pemanggilankuadrat(a). Compiler dapat menggantinya langsung dengana * a, menghindari overhead pemanggilan fungsi. - Header boleh di-include berkali-kali: karena fungsi bersifat
static, setiap translation unit yang meng-include header mendapatkan salinan lokal fungsi. Linker tidak melihat konflik karena simbolkuadratdi setiap object file bersifat internal (huruftkecil dinm).
Pola inline Non-Static dengan Definisi Eksternal #
Standar C99 memperkenalkan pola inline non-static yang lebih kompleks. Definisi inline di header tidak menyebabkan multiple definition karena bersifat inline definition—tetapi compiler tidak wajib menyediakan simbol eksternal untuk fungsi. Untuk memungkinkan alamat fungsi diambil (mis. untuk function pointer), kita perlu mendeklarasikan extern inline di salah satu file .c untuk memaksa definisi eksternal.
File util.h:
#ifndef UTIL_H
#define UTIL_H
/* inline tanpa static: definisi boleh di header, tetapi butuh
deklarasi extern di file .c untuk memberi definisi eksternal */
inline int tambah_inline(int a, int b) {
return a + b;
}
#endifFile util.c:
#include "util.h"
/* Mendefinisikan ulang untuk ekspor simbol ke linker */
extern inline int tambah_inline(int a, int b);File main.c:
#include <stdio.h>
#include "util.h"
int main(void) {
printf("tambah_inline(3, 4) = %d\n", tambah_inline(3, 4));
return 0;
}Kompilasi dan jalankan:
gcc -std=c11 -Wall -Wextra -I. -o app main.c util.c && ./appOutput yang Dihasilkan:
tambah_inline(3, 4) = 7Perhatikan bahwa util.c hanya berisi satu baris extern inline int tambah_inline(int a, int b); tanpa badan fungsi. Deklarasi ini memberitahu compiler untuk menyediakan definisi eksternal fungsi—definisi yang akan dipakai jika alamat fungsi diambil atau jika compiler lain memilih untuk tidak meng-inline. Pola ini lebih kompleks daripada static inline dan jarang dipakai pada proyek modern; kebanyakan kode memilih pola static inline di header untuk kesederhanaan.
Perbandingan dengan Macro Berparameter #
Inline function dan macro berparameter sering dianggap sebagai pilihan alternatif. Namun, keduanya berbeda dalam beberapa aspek penting:
| Aspek | static inline function | Macro berparameter |
|---|---|---|
| Pemeriksaan tipe | Ya, oleh compiler | Tidak, hanya substitusi teks |
| Side effect ganda | Tidak—argumen dievaluasi sekali | Ya—argumen dapat dievaluasi berkali-kali |
| Debugger | Bisa step into fungsi | Sulit—kode tidak terlihat sebagai entitas terpisah |
| Scope variabel | Mengikuti aturan C | Hanya teks, dapat bocor |
| Tipe generik | Tidak, tipe tertentu | Ya, polimorfik ala teks |
| Ukuran translation unit | Bergantung pada inline decision | Selalu mengembang |
Untuk operasi yang membutuhkan tipe generik (mis. MAX untuk int, double, char), macro berparameter masih relevan. Untuk operasi yang dapat didefinisikan dengan tipe tertentu, static inline lebih aman dan lebih mudah di-debug. Standar C11 juga memperkenalkan _Generic yang memungkinkan kita menulis macro generik yang memilih fungsi static inline berdasarkan tipe—solusi terbaik dari kedua dunia.