Operator

Operator aritmetika, relasional, logika, bitwise, ternary, dan sizeof beserta aturan prioritasnya.

Daftar isi

Operator adalah simbol yang menggabungkan nilai menjadi ekspresi (expression) baru, misalnya a + b yang menghasilkan jumlah dua variabel. Topik ini membahas kelompok operator aritmetika, relasional, logika, bitwise, ternary, dan sizeof, ditutup dengan aturan prioritas yang menentukan urutan evaluasi. Setelah membacanya, ekspresi bertingkat dapat ditulis dan dibaca sambil mengetahui hasil yang diharapkan, termasuk jebakan umum seperti pembagian bulat dan tertukarnya = dengan ==.

Operator aritmetika#

Operator aritmetika terdiri atas +, -, *, /, dan %, ditambah operator penugasan gabungan seperti += serta operator penaikan ++. Program berikut menguji semuanya pada nilai yang mudah dihitung ulang:

c aritmetika.c
#include <stdio.h>

int main(void) {
    int a = 7;
    int b = 2;
    double x = 7.0;
    double y = 2.0;

    printf("a + b   = %d\n", a + b);
    printf("a - b   = %d\n", a - b);
    printf("a * b   = %d\n", a * b);
    printf("a / b   = %d\n", a / b);
    printf("a %% b   = %d\n", a % b);
    printf("x / y   = %.1f\n", x / y);
    printf("-7 / 2  = %d\n", -7 / 2);
    printf("-7 %% 2  = %d\n", -7 % 2);

    a += 10;
    printf("a += 10 -> %d\n", a);
    a++;
    printf("a++     -> %d\n", a);
    return 0;
}
text Keluaran
a + b   = 9
a - b   = 5
a * b   = 14
a / b   = 3
a % b   = 1
x / y   = 3.5
-7 / 2  = -3
-7 % 2  = -1
a += 10 -> 17
a++     -> 18

Baris kelima dan keenam memperlihatkan aturan terpenting kelompok ini, yaitu 7 / 2 menghasilkan 3 karena pembagian dua bilangan bulat membuang bagian pecahannya, sedangkan 7.0 / 2.0 menghasilkan 3.5 karena operan bertipe pecahan. Tipe hasil mengikuti operan yang lebih luas, sehingga mencampur satu operan pecahan sudah cukup untuk mendapatkan hasil pecahan. Perilaku pembagian bulat juga berlaku untuk bilangan negatif dengan memotong menuju nol, sehingga -7 / 2 menghasilkan -3, bukan -4. Operator % menghasilkan sisa pembagian dan tanda hasilnya mengikuti operan kirinya, sehingga -7 % 2 menghasilkan -1.

Tanda % pada printf bertindak sebagai awal penentu format, sehingga untuk mencetak karakter persen itu sendiri harus ditulis ganda menjadi %%, sebagaimana terlihat pada baris sisa pembagian di atas.

Operator relasional dan logika#

Operator relasional membandingkan dua nilai dan selalu menghasilkan angka, yaitu 1 untuk benar dan 0 untuk salah. Adapun operator logika && (dan), || (atau), dan ! (bukan) menggabungkan hasil-hasil perbandingan tersebut. Pada kondisi seperti if, angka nol dianggap salah dan angka bukan nol dianggap benar. Karena hasil perbandingan adalah angka biasa, hasil itu juga dapat ditampung di dalam variabel int dan diperiksa lagi kemudian:

c logika-bitwise.c
#include <stdio.h>

int main(void) {
    printf("5 > 3  -> %d\n", 5 > 3);
    printf("2 == 4 -> %d\n", 2 == 4);
    printf("1 && 0 -> %d\n", 1 && 0);
    printf("1 || 0 -> %d\n", 1 || 0);
    printf("!0     -> %d\n", !0);

    printf("12 & 10 = %d\n", 12 & 10);
    printf("12 | 10 = %d\n", 12 | 10);
    printf("12 ^ 10 = %d\n", 12 ^ 10);
    printf("1 << 3  = %d\n", 1 << 3);
    printf("16 >> 2 = %d\n", 16 >> 2);
    return 0;
}
text Keluaran
5 > 3  -> 1
2 == 4 -> 0
1 && 0 -> 0
1 || 0 -> 1
!0     -> 1
12 & 10 = 8
12 | 10 = 14
12 ^ 10 = 6
1 << 3  = 8
16 >> 2 = 4

Operator logika pada C memiliki sifat evaluasi pintas (short circuit), yaitu sisi kanan tidak dieksekusi bila hasilnya sudah pasti dari sisi kiri. Untuk &&, sisi kanan dilewati bila sisi kiri salah, dan untuk || sisi kanan dilewati bila sisi kiri benar. Sifat ini bukan sekadar penghematan waktu, melainkan pencegahan kesalahan pada operasi yang berisiko:

c Contoh: evaluasi pintas mencegah pembagian nol
// tidak-dijalankan
// sisi kanan && hanya dihitung bila n bukan nol
int aman = (n != 0) && (total / n > 10);

Apabila n bernilai nol, perbandingan total / n > 10 tidak pernah dihitung, sehingga pembagian nol tidak pernah terjadi.

Satu jebakan pada kelompok ini adalah menulis perbandingan berantai dengan gaya matematika, misalnya 0 <= x <= 10. Ekspresi itu dihitung dari kiri, yaitu 0 <= x menghasilkan 0 atau 1 yang kemudian dibandingkan dengan 10, dan hasilnya selalu benar karena angka tersebut pasti kurang dari atau sama dengan 10. Rentang semacam ini harus ditulis sebagai dua perbandingan yang digabungkan, yaitu 0 <= x && x <= 10.

Operator bitwise#

Kelima baris terakhir program di atas memakai operator bitwise, yaitu operator yang bekerja pada tingkat bit bilangan bulat. Operator & (AND), | (OR), dan ^ (XOR) membandingkan kedua operan bit demi bit, sedangkan << dan >> menggeser seluruh bit ke kiri atau ke kanan. Cara termudah membacanya adalah menuliskan kedua operan dalam biner:

text Biner dari 12 dan 10
12 = 1100
10 = 1010
12 & 10 = 1000 = 8
12 | 10 = 1110 = 14
12 ^ 10 = 0110 = 6

Pergeseran kiri sebanyak satu bit sama efeknya dengan menggandakan nilai, sehingga 1 << 3 menghasilkan 8. Pergeseran kanan pada bilangan positif sama efeknya dengan pembagian bulat oleh pangkat dua, sehingga 16 >> 2 menghasilkan 4. Pada kompiler modern, perkalian dengan pangkat dua memang biasanya sudah otomatis diubah menjadi pergeseran, sehingga penulisan pergeseran secara manual lebih sering soal kejelasan maksud daripada kecepatan. Operator kelompok ini menjadi fondasi teknik pengaturan bit (bit manipulation), misalnya menampung banyak nilai benar-salah dalam satu bilangan, yang dibahas lebih lanjut pada modul Preprosesor.

Operator ternary dan sizeof#

Operator ternary ? : adalah satu-satunya operator dengan tiga operan, dan bentuknya mempersingkat percabangan sederhana. Polanya adalah kondisi ? nilai_jika_benar : nilai_jika_salah. Adapun sizeof menghasilkan ukuran dalam byte dari sebuah tipe maupun ekspresi, dan hasilnya bertipe size_t yang dicetak dengan %zu. Program berikut menguji keduanya beserta perbedaan i++ dan ++i:

c operator-lain.c
#include <stdio.h>

int main(void) {
    int nilai = 75;
    int i = 5;

    printf("Status: %s\n", nilai >= 60 ? "Lulus" : "Ulang");
    printf("sizeof(int) = %zu byte\n", sizeof(int));

    int a = i++;
    int b = ++i;
    printf("a = %d, b = %d\n", a, b);

    printf("2 + 3 * 4   = %d\n", 2 + 3 * 4);
    printf("(2 + 3) * 4 = %d\n", (2 + 3) * 4);
    return 0;
}
text Keluaran
Status: Lulus
sizeof(int) = 4 byte
a = 5, b = 7
2 + 3 * 4   = 14
(2 + 3) * 4 = 20

Baris a = i++ memakai bentuk pascanaik, yaitu nilai lama 5 yang diambil untuk a sebelum i dinaikkan. Baris b = ++i memakai bentuk pranaik, yaitu i dinaikkan lebih dahulu menjadi 7 sebelum nilainya diambil untuk b. Hasil a = 5, b = 7 menunjukkan bahwa urutan itulah satu-satunya perbedaan keduanya. Bila penaikan berdiri sendiri sebagai pernyataan tanpa nilai yang dipakai, keduanya sama saja, dan bentuk pascanaik i++ menjadi pilihan yang paling umum. Operator ternary sebaiknya tidak disarangkan, karena tanda tanya bertingkat cepat sulit dibaca dan percabangan biasa menjadi pilihan yang lebih jelas pada kasus tersebut.

Prioritas operator#

Ketika satu ekspresi memuat beberapa operator, aturan prioritas (precedence) menentukan operator mana yang dihitung lebih dahulu. Perkalian dan pembagian memiliki prioritas lebih tinggi daripada penjumlahan, sehingga 2 + 3 * 4 menghasilkan 14, bukan 20, sebagaimana dua baris terakhir program di atas. Prioritas operator yang paling sering ditemui dirangkum berikut ini, dari yang tertinggi.

TingkatOperator
1() tanda kurung
2!, sizeof, unary +, unary -, ++, --
3*, /, %
4+, -
5<<, >>
6<, <=, >, >=
7==, !=
8&&
9||
10? :
11=, +=, -=, dan kawan-kawannya

Perbandingan memiliki prioritas lebih tinggi daripada logika, sehingga x > 0 && x < 10 dievaluasi sebagai (x > 0) && (x < 10) tanpa perlu tanda kurung. Meskipun demikian, menuliskan tanda kurung pada ekspresi yang mencampur lebih dari dua kelompok operator tetap dianjurkan karena membuat maksud penulisnya terbaca tanpa perlu menghafal tabel.

Kesalahan umum#

Kesalahan paling terkenal pada kelompok operator adalah menulis satu tanda = di tempat yang dimaksudkan sebagai perbandingan ==. Tanda = adalah operator penugasan yang mengubah nilai variabelnya, dan hasil penugasan itulah yang dipakai sebagai kondisi. Program berikut memperlihatkan akibatnya:

c jebakan-samadengan.c
#include <stdio.h>

int main(void) {
    int nilai = 75;

    if (nilai = 0) {
        printf("Cabang ini ikut dieksekusi\n");
    }
    printf("Nilai sekarang: %d\n", nilai);
    return 0;
}
text Keluaran
Nilai sekarang: 0

Percabangan tidak dieksekusi karena hasil penugasan nilai = 0 adalah angka nol yang berarti salah, dan yang lebih serius, nilai nilai ikut rusak menjadi 0. Kompilasi dengan opsi -Wall menangkap pola ini sejak awal:

text Pesan warning gcc -Wall
jebakan-samadengan.c: In function ‘main’:
jebakan-samadengan.c:6:9: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
    6 |     if (nilai = 0) {
      |         ^~~~~

Pesan suggest parentheses around assignment used as truth value muncul persis pada baris tersebut. Kebiasaan mengompilasi dengan -Wall dan membaca setiap warning-nya menangkap kesalahan kelas ini sebelum program dijalankan.

Kesalahan kedua adalah pembagian bilangan bulat dengan nol. Berbeda dengan tipe pecahan yang menghasilkan nilai khusus berupa tak hingga, pembagian int dengan nol adalah perilaku tak terdefinisi dan umumnya menghentikan program mendadak. Penyebut nol sebaiknya dicek dengan percabangan atau evaluasi pintas sebelum operasi pembagian dilakukan, sebagaimana pola pada bagian operator logika. Kesalahan ketiga yang lazim adalah memakai % pada operan pecahan, karena operator ini hanya berlaku untuk bilangan bulat dan pemaksaannya langsung ditolak kompiler.

Ringkasan#

  • Pembagian dua bilangan bulat membuang pecahannya menuju nol, dan % menghasilkan sisa pembagian dengan aturan tanda yang mengikuti operan kirinya.
  • Perbandingan menghasilkan 1 atau 0, operator && dan || mengevaluasi pintas sehingga sisi kanan bisa dilewati.
  • Operator bitwise bekerja per bit, dan pergeseran kiri menggandakan nilai sedangkan pergeseran kanan membaginya untuk bilangan positif.
  • i++ mengambil nilai lama sebelum menaikkan, sedangkan ++i menaikkan lebih dahulu, dan ? : mempersingkat percabangan dua pilihan.
  • Prioritas menentukan urutan evaluasi, dan -Wall menangkap jebakan tertukarnya = dengan ==.

Referensi#