Operator adalah kata kerjanya C: operator menerima nilai dan menghasilkan nilai baru. Jumlahnya sekitar 40, tapi selusin saja sudah mencakup kebanyakan kode, dan dua di antaranya punya jebakan yang cukup tajam sampai layak dibahas di bagian tersendiri.
Operator aritmetika
(%% di format string mencetak tanda persen apa adanya: % saja akan memulai format specifier.)
Lima operator aritmetika biner adalah + - * / %, ditambah - unary untuk negasi dan + yang pada dasarnya tidak melakukan apa-apa.
Jebakan pembagian integer
a / b dengan dua integer melakukan pembagian integer dan membuang sisanya. Tidak ada pembulatan: hasilnya dipotong ke arah nol.
Kasus terakhir itulah bug yang lolos sampai ke production. Menyimpan hasilnya ke double tidak membantu: pembagian total / count sudah selesai, dan sudah berupa int, sebelum penugasan terjadi. Perbaikannya adalah menjadikan salah satu operand floating point di dalam ekspresinya, biasanya dengan cast.
Ada dua aturan terkait: membagi integer dengan nol adalah undefined behavior dan biasanya membuat program crash, dan INT_MIN / -1 menyebabkan overflow.
Operator modulus
% menghasilkan sisa bagi dan hanya bekerja untuk integer:
Menguji x % 2 == 0 untuk bilangan genap dan memakai % n untuk memutar indeks kembali ke awal array adalah dua pemakaian sehari-harinya.
Dengan angka negatif, % di C mengikuti tanda bilangan yang dibagi:
Jadi x % 2 == 1 adalah uji bilangan ganjil yang rusak kalau x bisa negatif: -7 % 2 hasilnya -1. Pakai x % 2 != 0 sebagai gantinya.
Untuk sisa bagi floating point, % adalah error kompilasi; pakai fmod() dari math.h.
Penugasan dan penugasan gabungan
= menyimpan sebuah nilai. Bentuk gabungannya menyatukan sebuah operasi dengan penyimpanan:
x += 5 berarti x = x + 5, tapi x hanya dievaluasi sekali, dan itu penting saat targetnya sesuatu seperti arr[compute_index()].
Penugasan sendiri adalah ekspresi yang menghasilkan nilai yang diberikan. Karena itulah a = b = c = 0 bekerja (penugasannya dari kanan ke kiri), dan karena itu juga kesalahan = versus == bisa dikompilasi tanpa peringatan.
Increment dan decrement
++ menambah satu, -- mengurangi satu. Masing-masing punya bentuk prefix dan postfix:
Sebagai pernyataan yang berdiri sendiri, keduanya bisa saling menggantikan, dan i++ jadi pilihan yang lazim di header for hanya karena tradisi.
Yang tidak boleh kamu lakukan adalah memakai sebuah variabel lebih dari sekali dalam ekspresi yang juga mengubahnya:
int i = 5;
int x = i++ + i++; /* undefined behavior */
arr[i] = i++; /* undefined behavior */
printf("%d %d", i++, i);/* undefined behavior */
C tidak mendefinisikan urutan evaluasi subekspresi-subekspresi itu, jadi hasilnya bukan sekadar tidak ditentukan: perilaku seluruh program menjadi undefined. Pecah pernyataannya menjadi dua dan ambiguitasnya hilang.
Operator perbandingan
Ada enam, dan semuanya menghasilkan int: 1 untuk benar dan 0 untuk salah.
Hasil yang berupa int biasa, bukan tipe boolean khusus, adalah ciri khas C. Lihat halaman boolean di C untuk akibatnya, termasuk bug = versus ==.
Ada dua kesalahan perbandingan yang khas C. Perbandingan berantai tidak bekerja seperti di matematika: if (1 < x < 10) selalu benar, karena 1 < x dievaluasi menjadi 0 atau 1, lalu hasil itu dibandingkan dengan 10. Tulis if (x > 1 && x < 10). Lalu membandingkan string dengan == membandingkan pointer, bukan teks: pakai strcmp dari string.h.
Operator logika
&& adalah AND, || adalah OR, ! adalah NOT. Ketiganya menganggap nilai apa pun yang bukan nol sebagai benar.
Operator ini melakukan short-circuit: && berhenti begitu satu operand bernilai salah, dan || berhenti begitu satu operand bernilai benar. Sisanya tidak pernah dievaluasi. Ini bukan sekadar optimasi, tapi jaminan yang bisa kamu andalkan demi keamanan:
Tukar urutan kedua uji itu, dan pemanggilan dengan NULL akan melakukan dereference null pointer lalu crash. Jaga dulu, baru pakai: urutan di rantai && adalah bagian dari logikanya.
Operator kondisional
Satu-satunya operator tiga operand di C memilih di antara dua nilai:
condition ? value_if_true : value_if_false. Ini ekspresi, jadi bisa ditaruh di tempat pernyataan if tidak bisa: di dalam argumen printf, atau di inisialisasi. Buat tetap singkat; operator kondisional bersarang cepat sekali jadi sulit dibaca.
Operator bitwise, sekilas
Operator ini bekerja pada bit-bit individual sebuah integer:
Operator ini dipakai untuk flag, mask, dan register hardware. Ada dua peringatan: & dan | bukan && dan || (keduanya tidak melakukan short-circuit dan bekerja bit demi bit), dan menggeser nilai bertanda (signed) atau menggeser lebih jauh dari lebar tipenya adalah undefined. Pakai tipe unsigned untuk pekerjaan bit.
Prioritas operator
Saat sebuah ekspresi tidak punya tanda kurung, tabel inilah yang menentukan apa terikat ke apa. Prioritas tertinggi lebih dulu:
| Tingkat | Operator | Asosiativitas |
|---|---|---|
| 1 | () [] -> . x++ x-- | kiri ke kanan |
| 2 | ! ~ ++x --x +x -x *p &x sizeof (type) | kanan ke kiri |
| 3 | * / % | kiri ke kanan |
| 4 | + - | kiri ke kanan |
| 5 | << >> | kiri ke kanan |
| 6 | < <= > >= | kiri ke kanan |
| 7 | == != | kiri ke kanan |
| 8 | & | kiri ke kanan |
| 9 | ^ | kiri ke kanan |
| 10 | OR bitwise | kiri ke kanan |
| 11 | && | kiri ke kanan |
| 12 | OR logika | kiri ke kanan |
| 13 | ?: | kanan ke kiri |
| 14 | = += -= *= /= %= dan sejenisnya | kanan ke kiri |
| 15 | , | kiri ke kanan |
Konsekuensi praktisnya:
a + b * c /* means a + (b * c) */
a < b == c < d /* means (a < b) == (c < d) - rarely what you meant */
x & 1 == 0 /* means x & (1 == 0), i.e. x & 0 - a classic bug */
*p++ /* means *(p++) - dereference p, then advance it */
Baris ketiga itu layak dihafal: == terikat lebih kuat daripada &, jadi uji bitmask butuh tanda kurung: (x & 1) == 0.
Tidak ada yang ingat kelima belas tingkat itu, dan memang tidak perlu. Pelajari bahwa * mengalahkan +, bahwa perbandingan mengalahkan && yang mengalahkan ||, dan bahwa sisanya diberi tanda kurung:
if ((flags & MASK) != 0 && (count > 0 || force)) { ... }
Baris itu punya tanda kurung yang berlebihan, dan justru jadi lebih baik karenanya.
Pertanyaan yang sering diajukan
Apa fungsi % di C?
% adalah operator modulus: hasilnya sisa pembagian integer. 17 % 5 hasilnya 2. Operator ini hanya bekerja untuk integer: memakainya pada float atau double adalah error kompilasi, dan fmod() dari math.h adalah padanannya untuk floating point.
Kenapa 5 / 2 hasilnya 2 di C?
Karena kedua operandnya integer, jadi C melakukan pembagian integer dan membuang pecahannya. Jadikan salah satu sisinya nilai floating point untuk mendapat 2,5: 5 / 2.0, atau cast salah satu operandnya dengan (double)a / b.
Apa bedanya i++ dan ++i?
Keduanya menambahkan satu ke i. ++i (prefix) menaikkan nilainya dulu lalu menghasilkan nilai baru; i++ (postfix) menghasilkan nilai lama lalu menaikkannya sesudahnya. Sebagai pernyataan yang berdiri sendiri keduanya identik: perbedaannya hanya penting saat hasilnya dipakai, seperti pada int b = a++; dibandingkan int b = ++a;.
Apa itu prioritas operator di C?
Urutan operator terikat saat sebuah ekspresi tidak punya tanda kurung. *, /, dan % terikat lebih kuat daripada + dan -, yang terikat lebih kuat daripada perbandingan, yang terikat lebih kuat daripada &&, lalu ||, lalu penugasan. Kalau ragu, tambahkan tanda kurung: tidak ada biayanya dan pertanyaannya langsung hilang.