C adalah bahasa yang dikompilasi: tidak ada yang berjalan sampai compiler menerjemahkan kode sumbermu menjadi kode mesin untuk CPU dan sistem operasimu. Langkah itu hanya satu perintah, tetapi memahami apa yang dilakukannya membuat sebagian besar pesan error berubah dari misterius menjadi jelas.
Dua Perintahnya
Simpan ini sebagai hello.c:
#include <stdio.h>
int main(void) {
printf("Hello, C!\n");
return 0;
}
Lalu, di folder yang sama:
gcc hello.c -o hello
./hello
Perintah pertama mengompilasi. Perintah kedua menjalankan hasilnya. Di Windows, perintah untuk menjalankannya adalah hello di Command Prompt atau .\hello di PowerShell. Tidak ada awalan ./, karena Windows secara default mencari di direktori saat ini, sedangkan shell Unix sengaja tidak melakukannya.
Kalau kamu tidak menulis -o hello, gcc menamai output-nya a.out (atau a.exe), karena itulah tutorial lama diakhiri dengan ./a.out. Selalu beri nama output-mu; hanya butuh empat karakter dan menghindarkan kebingungan.
Berikut program yang sama di editor browser, yang mengerjakan kedua langkah itu untukmu:
Apa yang Sebenarnya Dilakukan "Kompilasi"
gcc hello.c -o hello terlihat seperti satu langkah. Sebenarnya ada empat, dan masing-masing bisa gagal dengan jenis error-nya sendiri.
1. Preprocessing. Sebelum kode C apa pun dikompilasi, preprocessor menangani setiap baris yang diawali #. #include <stdio.h> benar-benar diganti dengan isi file header itu; macro #define dijabarkan; blok #ifdef dipertahankan atau dihapus. Hasilnya adalah satu file C besar tanpa baris # yang tersisa. Kamu bisa melihatnya:
gcc -E hello.c
Perintah itu mencetak ratusan baris, dan hampir semuanya adalah stdio.h yang ditempelkan.
2. Kompilasi. Kode C hasil preprocessing di-parse, diperiksa tipenya, dan diterjemahkan menjadi assembly untuk CPU-mu. Di sinilah error sintaks, error tipe, dan peringatan berasal.
3. Assembling. Assembly menjadi object file: kode mesin dengan tempat kosong di bagian yang memanggil fungsi dari file lain.
gcc -c hello.c # produces hello.o, stops before linking
4. Linking. Object file digabungkan dengan library standar C, setiap tempat kosong diisi dengan alamat sungguhan, dan hasilnya adalah executable. Di sinilah error "undefined reference" berasal.
Pelajaran praktisnya: error kompilasi menunjuk ke sebuah baris di kode sumbermu, sedangkan error linking tidak, karena linking terjadi setelah setiap baris sudah diterima.
Flag yang Layak Dipakai Sejak Hari Pertama
gcc file.c -o prog tanpa tambahan apa pun menerima banyak kode berbahaya tanpa suara. Empat flag mengubah hal itu.
gcc -std=c17 -Wall -Wextra -g hello.c -o hello
-Wallmenyalakan peringatan yang umum. Meski namanya begitu, ini bukan "semua" peringatan, melainkan kumpulan yang masuk akal.-Wextramenambahkan lebih banyak lagi, termasuk parameter yang tidak dipakai dan beberapa kesalahan perbandingan.-std=c17mengunci standar bahasa agar kodemu berarti sama di setiap mesin. Gunakan-std=c99kalau kamu mengikuti materi yang lebih lama.-gmenyimpan informasi debugging, sehinggagdbataulldbbisa menampilkan baris kode sumbermu yang sebenarnya saat terjadi crash.
Dua lagi yang nantinya akan kamu butuhkan:
-O2menyalakan optimasi untuk build release. Matikan selama belajar: kode yang dioptimasi lebih sulit di-debug, dan peringatan kadang bergeser.-fsanitize=address,undefined(gcc dan clang) membuat program berhenti dengan pesan yang jelas tepat saat ia membaca di luar batas atau mengalami undefined behavior. Ini satu-satunya flag paling berguna untuk belajar C.
Coba sendiri peringatannya. Program ini bisa dikompilasi dan dijalankan, tetapi ada dua bug sungguhan:
count tidak pernah diberi nilai, jadi program mencetak byte apa pun yang kebetulan ada di sana. Dengan -Wall, compiler memberitahukannya: 'count' is used uninitialized. Peringatan di C hampir tidak pernah sekadar gangguan; anggap saja sebagai error yang belum kamu alami.
Mengompilasi Lebih dari Satu File
Program sungguhan dipecah menjadi beberapa file. Berikan semuanya ke gcc:
gcc -std=c17 -Wall main.c utils.c -o myprog
Atau kompilasi masing-masing secara terpisah lalu link di akhir. Itulah yang dilakukan build system agar perubahan di satu file tidak membuat semuanya di-build ulang:
gcc -c main.c # -> main.o
gcc -c utils.c # -> utils.o
gcc main.o utils.o -o myprog
Beberapa library butuh flag link yang eksplisit. Library math adalah yang pasti ditemui setiap pemula:
gcc calc.c -o calc -lm
Tanpa -lm, memakai sqrt dari math.h bisa dikompilasi dengan lancar lalu gagal saat linking dengan undefined reference to sqrt: deklarasinya ada di header, tetapi kodenya ada di library yang tidak diminta siapa pun.
Membaca Error
Error di C singkat tetapi konsisten. Tiga contoh berikut mencakup sebagian besar yang akan kamu lihat di awal.
Titik koma yang hilang dilaporkan di baris berikutnya, karena compiler terus membaca:
hello.c:5:5: error: expected ';' before 'return'
Perbaikannya ada di baris 4, bukan baris 5. Setiap kali error menunjuk ke baris yang terlihat benar, periksa baris sebelumnya.
Header yang hilang terlihat seperti misteri tentang fungsi yang jelas sudah kamu tulis dengan benar:
hello.c:4:5: warning: implicit declaration of function 'printf'
Artinya compiler tidak pernah melihat deklarasi untuk printf, jadi kamu lupa #include <stdio.h>. Di C99 dan sesudahnya, ini error, bukan sekadar peringatan.
Kegagalan linking sama sekali tidak punya nomor baris:
/usr/bin/ld: main.o: in function `main':
main.c:(.text+0x1a): undefined reference to `helper'
Compiler percaya padamu bahwa helper ada di suatu tempat; linker mencarinya dan ternyata tidak ada. Entah kamu tidak pernah menulis definisinya, mengejanya berbeda, atau lupa memberikan file yang berisi definisi itu ke gcc.
Selalu perbaiki error yang pertama. Error C berantai: satu baris yang salah bisa menghasilkan dua puluh pesan, dan sembilan belas di antaranya hilang begitu yang pertama diperbaiki.
Exit Code
return 0 dari main bukan hiasan. Itu adalah status keluar program, dan shell bisa membacanya:
Setelah menjalankannya, echo $? di macOS/Linux (atau echo %errorlevel% di Windows) mencetak angka itu. Script dan build tool memakainya untuk memutuskan apakah proses dilanjutkan. Konvensinya mutlak: 0 berarti sukses, dan bukan nol adalah kode error yang kamu pilih sendiri. stdlib.h mendefinisikan EXIT_SUCCESS dan EXIT_FAILURE kalau kamu lebih suka memakai nama.
Sejak C99, mencapai akhir main tanpa return dianggap sebagai return 0. Tetapi menuliskannya lebih jelas, dan untuk fungsi lain hal itu wajib.
Pertanyaan yang sering diajukan
Bagaimana cara compile dan menjalankan program C?
Simpan kodenya sebagai hello.c, lalu jalankan gcc hello.c -o hello untuk mem-build-nya dan ./hello untuk menjalankannya (cukup hello di Windows). Kalau gcc tidak ditemukan, kamu perlu menginstal compiler lebih dulu, atau gunakan compiler C online.
Apa fungsi gcc -o?
-o memberi nama file output. gcc hello.c -o hello menghasilkan executable bernama hello. Tanpa -o, gcc menulis ke a.out (atau a.exe di Windows), karena itulah banyak tutorial lama menjalankan ./a.out.
Flag gcc apa yang sebaiknya selalu dipakai?
gcc -std=c17 -Wall -Wextra -g yourfile.c -o yourprog. -Wall -Wextra menyalakan peringatan yang menangkap bug sungguhan, -std=c17 mengunci versi bahasa, dan -g menyimpan simbol debug agar debugger bisa menampilkan kode sumbermu. Tambahkan -O2 kalau kamu ingin kecepatan di build release.
Apa arti "undefined reference to" di C?
Itu error linker: compiler menerima pemanggilan sebuah fungsi, tetapi definisi fungsi itu tidak ditemukan. Penyebab umumnya adalah salah ketik pada nama, lupa mengompilasi file .c kedua, atau memakai fungsi matematika tanpa me-link library math (-lm).