Sebelum debugger dan sanitizer bekerja, compiler sudah berjalan lebih dulu di garis depan — dan bila kita izinkan, ia melaporkan puluhan pola kode yang “sah secara bahasa tetapi nyaris pasti salah”. Peringatan (warning) berbeda dari error: compiler tetap menghasilkan executable, sehingga mudah terlewat atau diabaikan begitu saja. Kebiasaan profesional yang ingin kita bangun di chapter ini adalah memperlakukan peringatan sebagai pekerjaan rumah yang harus lunas sebelum program dijalankan, dimulai dari tiga flag standar: -Wall, -Wextra, dan -Wpedantic.
Mengaktifkan Peringatan Secara Penuh #
Secara bawaan, g++ cukup diam. Flag di bawah ini yang akan kita pakai sepanjang course — tambahkan -Wpedantic bila kode perlu dipindah antar compiler:
g++ -std=c++23 -Wall -Wextra -Wpedantic program.cpp -o program-Wall: bukan “all warnings” secara harfiah, tetapi sekumpulan peringatan yang paling sering menandai bug nyata: variabel terpakai tanpa inisialisasi, lupa return, pembandingan tipe tak sepadan, dan sebagainya.-Wextra: lapisan kedua — lebih sensitif dan kadang berisik, misalnya parameter function yang tidak pernah dipakai.-Wpedantic: menolak ekstensi khusus compiler (GNU extension) agar kode tetap standar ISO dan portabel.
Berkas pertama kita sengaja memuat tiga pelanggaran yang paling umum di kode pemula. Perhatikan bahwa semuanya sah secara sintaks — tanpa flag, g++ 14.2 mengompilasinya tanpa sepatah kata pun:
// sebelum.cpp — sengaja penuh peringatan; kompilasi dengan -Wall -Wextra
// untuk melihat apa saja yang compiler temukan tanpa menghentikan build.
#include <iostream>
#include <vector>
int jumlahkan(const std::vector<int>& data) {
int total = 0;
for (std::size_t i = 0; i < data.size(); ++i) {
total += data[i];
}
// lupa return total — -Wreturn-type akan muncul di sini
}
int main() {
int kunciRahasia = 42; // -Wunused-variable
std::vector<int> nilai = {4, 8, 15, 16, 23, 42};
std::size_t jumlahNilai = nilai.size();
if (jumlahNilai > -1) { // -Wsign-compare
std::cout << "jumlah elemen: " << jumlahNilai << "\n";
}
return 0;
}Kompilasi berikut adalah hasil nyata dari g++ -std=c++23 -Wall -Wextra sebelum.cpp -o sebelum di g++ 14.2 — perhatikan baris, kolom, dan tag -W... di ujung tiap pesan:
sebelum.cpp: In function ‘int jumlahkan(const std::vector<int>&)’:
sebelum.cpp:13:1: warning: no return statement in function returning non-void [-Wreturn-type]
13 | }
| ^
sebelum.cpp: In function ‘int main()’:
sebelum.cpp:19:21: warning: comparison of integer expressions of different signedness: ‘std::size_t’ {aka ‘long unsigned int’} and ‘int’ [-Wsign-compare]
19 | if (jumlahNilai > -1) { // -Wsign-compare
| ~~~~~~~~~~~~^~~~
sebelum.cpp:16:9: warning: unused variable ‘kunciRahasia’ [-Wunused-variable]
16 | int kunciRahasia = 42; // -Wunused-variable
| ^~~~~~~~~~~~Membedah Tiga Kelas Peringatan #
-Wreturn-type(baris 13): functionjumlahkanbertipeinttetapi bisa berakhir tanpareturn. Bila pemanggil memakai nilai kembaliannya, itu undefined behavior — program boleh membaca “nilai sampah” dari register. Ini peringatan yang hampir selalu berbahaya; perbaiki dengan menambahreturn total;.-Wsign-compare(baris 19):jumlahNilaibertanda tak-positif (std::size_t) dibandingkan dengan-1yang bertanda positif-negatif (int). Dalam perbandingan campuran, compiler mengubah-1menjadi angka raksasa, sehinggajumlahNilai > -1tak mungkin salah — kondisi yang berlawanan dengan niat penulisnya. Bug perbandingan tipe seperti ini pernah merembes ke sistem sungguhan bertahun-tahun tanpa ketahuan.-Wunused-variable(baris 16):kunciRahasiadiberi nilai tetapi tak pernah dibaca. Kelas ini minor — biasanya sisa refaktor — tetapi kadang menjadi petunjuk ada variabel yang seharusnya dipakai dan salah ketik nama.
Peringatan yang Baru Muncul Saat Optimasi #
Sebagian analisis butuh data aliran yang baru tersedia pada tahap optimasi. Program kecil ini lolos bersih di -O0, lalu dihajar compiler di -O2:
#include <iostream>
int bagi(int a, int b) {
int hasil;
if (b != 0) {
hasil = a / b;
}
return hasil; // jalur b == 0 tidak pernah mengisi hasil
}
int main() {
std::cout << bagi(10, 2) << "\n";
return 0;
}bagi.cpp: In function ‘int bagi(int, int)’:
bagi.cpp:8:12: warning: ‘hasil’ may be used uninitialized [-Wmaybe-uninitialized]
8 | return hasil; // jalur b == 0 tidak pernah mengisi hasil
| ^~~~~
bagi.cpp:4:9: note: ‘hasil’ was declared here
4 | int hasil;
| ^~~~~Pelajaran dua lapis: pertama, variabel yang hanya terisi di sebagian jalur adalah perangkap klasik — isi nilai di deklarasi (int hasil = 0;) dan peringatan itu tidak akan pernah muncul. Kedua, build pengembangan dan build rilis sebaiknya sama-sama dikompilasi dengan flag peringatan penuh, karena keduanya menemukan set yang tidak identik. Dua peringatan lain yang perlu Anda kenali dari kelas “butuh konteks”: -Woverflow (nilai literal terpotong saat konversi, misalnya char c = 300; berubah menjadi 44) dan -Wpedantic, yang menampik ekstensi GNU seperti case range case 1 ... 5: dengan pesan range expressions in switch statements are non-standard.
-Werror: Peringatan yang Tidak Bisa Diabaikan #
Pada codebase bersama, cara paling efektif menegakkan disiplin adalah mengubah peringatan menjadi error sehingga build gagal keras:
sebelum.cpp: In function ‘int jumlahkan(const std::vector<int>&)’:
sebelum.cpp:13:1: error: no return statement in function returning non-void [-Werror=return-type]
13 | }
| ^
sebelum.cpp: In function ‘int main()’:
sebelum.cpp:19:21: error: comparison of integer expressions of different signedness: ‘std::size_t’ {aka ‘long unsigned int’} and ‘int’ [-Werror=sign-compare]
19 | if (jumlahNilai > -1) { // -Wsign-compare
| ~~~~~~~~~~~~^~~~
sebelum.cpp:16:9: error: unused variable ‘kunciRahasia’ [-Werror=unused-variable]
16 | int kunciRahasia = 42; // -Wunused-variable
| ^~~~~~~~~~~~
cc1plus: all warnings being treated as errorsKompilasi berhenti, tidak ada executable yang dihasilkan, dan tiap pesan kini berakhir di kategori error. Dalam pipeline CI, kombinasi -Wall -Wextra -Werror adalah pagar pertama kualitas kode sebelum sanitizers dan unit test bekerja. Bila satu peringatan tertentu terbukti palsu, kecualikan secara eksplisit dengan -Wno-<nama> atau pragma #pragma GCC diagnostic ignored — jangan matikan seluruh -Wall karena satu kasus.
Versi Bersih: Nol Peringatan #
File berikut memperbaiki ketiga masalah sebelum.cpp dan lolos -Wall -Wextra -Wpedantic tanpa satu pesan pun:
// sesudah.cpp — versi bersih: lolos -Wall -Wextra tanpa satu pun peringatan.
#include <iostream>
#include <vector>
int jumlahkan(const std::vector<int>& data) {
int total = 0;
for (const int& nilai : data) {
total += nilai;
}
return total; // perbaikan 1: nilai kembalian tidak lagi terlupa
}
int main() {
std::vector<int> nilai = {4, 8, 15, 16, 23, 42};
const std::size_t jumlahNilai = nilai.size();
std::cout << "jumlah elemen: " << jumlahNilai << "\n";
std::cout << "total: " << jumlahkan(nilai) << "\n";
// perbaikan 3: perbandingan memakai tipe bertanda yang setara
if (static_cast<int>(jumlahNilai) > 0) {
std::cout << "data tidak kosong\n";
}
return 0;
}Output yang Dihasilkan:
jumlah elemen: 6
total: 108
data tidak kosongTiga perbaikannya patut dicatat sebagai pola: return total; menutup jalur keluar function; variabel yang tidak dipakai dihapus sama sekali, bukan diberi komentar; dan perbandingan ditulis ulang agar kedua sisi punya tipe sepadan — static_cast<int>(jumlahNilai) > 0 aman karena jumlah elemen std::vector tidak mungkin melebihi rentang int dalam program wajar. Perhatikan juga loop yang kini memakai range-based for: menghapus indeks menghilangkan seluruh kelas soal tipe indeks.
Memilah Peringatan: Berbahaya vs Minor #
Tidak semua peringatan setara pentingnya, dan mengetahui urutan prioritasnya menjaga fokus saat laporan panjang menyambut Anda:
| Tag | Arti ringkas | Prioritas |
|---|---|---|
-Wreturn-type, -Wmaybe-uninitialized | jalur eksekusi menghasilkan nilai tidak tentu (UB) | berbahaya — tangani hari ini |
-Wsign-compare | perbandingan campuran tanda bisa membalik logika | tinggi |
-Woverflow | nilai literal/konversi terpotong | tinggi |
-Wunused-variable, -Wunused-parameter | sisa kode mati | minor — kebersihan |
-Wpedantic | memakai ekstensi non-standar | minor — isu portabilitas |
Peringatan compiler hanya bisa melihat satu berkas sekaligus dan tidak pernah menjalankan program. Bug yang hanya muncul saat eksekusi — pelanggaran memori, misalnya — butuh lapisan alat berikutnya: sanitizer runtime, yang kita kenal pada chapter berikutnya.
Referensi: GCC — Warning Options .