---
title: İşleçler
source: 'https://academia.sh/tr/kurslar/c-temelleri/islecler'
course: 'C Temelleri'
language: tr
updated: '2026-09-13T05:07:32+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Bir işlecin sonucunun işlenen tipine göre derlemede seçildiğini ölçerek gösterir'
    - 'Öncelik, kısa devre değerlendirmesi ve bileşik atamayı örnekle ayırt eder'
    - 'Değerlendirme sırasının hangi durumlarda tanımlı hangi durumlarda tanımsız olduğunu ayırır'
---

# İşleçler

Bir işlecin sonucunun işlenenlerin tipine göre derlemede karara bağlanması; öncelik, kısa devre değerlendirmesi, bileşik atama ve değerlendirme sırasının tanımlı-tanımsız ayrımı üzerinden ölçülmesi.

Değişkenler, Kapsam ve Ömür dersi, bir adın nereden göründüğünü ve bir değerin ne kadar
yaşadığını ölçtü — ikisi de bir *adın* durumuyla ilgiliydi. Bu ders bir adım öteye
geçiyor: iki değer bir işleçle birleştirildiğinde, sonucu neyin belirlediğini ölçüyor.
Yanıt, işlenenlerin değeri değil, tipidir — ve bu seçim, tıpkı önceki derste bir adın
hangi bildirime bağlandığı gibi, derlemede karara bağlanıyor. Bu ders dört ayrı işleç
ailesini — aritmetik, mantıksal, bitsel ve atama — aynı soruyla ölçüyor: kaynakta yazılan
bir işlecin sonucu, ya da o sonuca varmak için hangi alt işlemlerin çalışacağı, koşum
başlamadan önce ne kadarı zaten bellidir?

Programlama Temelleri kursu (M01/K02) aritmetik ve mantıksal işleçleri Python'la zaten
kurmuştu; orada bir işlecin davranışı çoğunlukla işlenenlerin çalışma zamanındaki
değerine bakılarak yorumlanırdı. C'nin karşılığı burada ölçülüyor: bir işlecin **hangi**
işlemi yürüteceği, kaynakta yazılan işlenenlerin **tipine** bakılarak, işlem hiç
çalışmadan önce derlemede sabitleniyor.

## İşlecin Tipe Göre Seçimi

Aynı `/` işleci, işlenenlerinin tipine göre iki farklı işlem yürütür: ikisi de tam sayıysa
tam sayı bölmesi, en az biri kayan noktalıysa kayan nokta bölmesi. Bu seçim veriye değil,
kaynakta yazılan tiplere bakılarak yapılıyor.

```c
// asama.c — islecin tipe gore secimi (kesit)
#include <stdio.h>

int main(void) {
    int tam = 7 / 2;
    double kesirli = 7 / 2.0;
    printf("tam %d kesirli %.1f\n", tam, kesirli);
    return 0;
}
```

```
tam 3 kesirli 3.5
```

**TS5.** Kaynakta yazılan tek fark, `2` ile `2.0` — biri tam sayı sabiti, öbürü kayan
nokta sabiti. Bu fark, hangi bölme işleminin çalışacağını derlemede belirliyor: `7 / 2`
tam sayı bölmesi yürütüyor ve kesirli kısmı atıyor, `7 / 2.0` ise `7`yi önce `double`a
yükseltip kayan nokta bölmesi yürütüyor. `7`nin kendisi hiç değişmedi; değişen, aynı `/`
işlecinin hangi donanım işlemine karşılık geldiği — kaynakta yazılan iki karakterlik
işleç sembolü aynı kalırken, derleyicinin ürettiği makine talimatı işlenenlerin tipine
göre iki farklı yol izliyor. Bu, önceki derste ölçülen tam sayı
yükseltmesiyle aynı ailede bir karar: işleç, işlenenlerin bildirilen tipine bakıyor,
çalışma zamanındaki değerine değil.

Bu kural yalnız bölme işlecine özgü değil; C standardının **olağan aritmetik
dönüşümler** dediği kural, hemen hemen bütün ikili aritmetik işleçler için aynı şekilde
işler. İki işlenenin tipi farklıysa, "dar" olan taraf "geniş" olana yükseltilir ve işlem
geniş tipte yürütülür — tıpkı Veri Tipleri dersinde `char` işlenenlerin `int`e
yükseltilmesi gibi, burada da bir `int` ile bir `double` toplandığında `int` önce
`double`a dönüştürülür. Kaynakta `tam_sayac + oran` gibi bir ifade yazıldığında, hangi
işlenenin hangi yöne dönüştürüleceği iki tarafın bildirilen tipine bakılarak
derlemede belirlenir; hangi değerlerin toplanacağı bu kararı hiç etkilemez.

## Öncelik: Kaynaktaki Yapının Derlemede Sabitlenmesi

Bir işlecin ne zaman çalışacağı yalnız tipe değil, kaynaktaki yapıya da bağlıdır.
Öncelik kuralları, parantezsiz bir ifadenin hangi alt ifadelerden önce
değerlendirileceğini belirler ve bu karar tamamen kaynağın kendisinde yazılıdır.

```c
// oncelik.c — islec onceligi kaynaktaki yapiyi derlemede sabitler
#include <stdio.h>

int main(void) {
    int carpma_once = 2 + 3 * 4;
    int toplama_once = (2 + 3) * 4;
    printf("%s %d\n", "carpma once (parantezsiz)", carpma_once);
    printf("%s %d\n", "toplama once (parantezli)", toplama_once);
    return 0;
}
```

```
carpma once (parantezsiz) 14
toplama once (parantezli) 20
```

İki ifade de aynı üç sayıyı (`2`, `3`, `4`) ve aynı iki işleci (`+`, `*`) taşıyor, ama
sonuçları farklı: `carpma_once` çarpmayı toplamadan önce yürütüyor (`2 + 12 = 14`),
`toplama_once` ise parantez sayesinde toplamayı önce yürütüyor (`5 * 4 = 20`). Bu fark
hiçbir veriye bakmadan, yalnız kaynaktaki parantezlerin varlığına bakılarak derlemede
çözülüyor — koşum başlamadan önce hangi alt ifadenin hangi sırada değerlendirileceği
zaten belli.

Öncelik yalnız hangi işlecin önce çalışacağını değil, aynı önceliğe sahip işleçler yan
yana yazıldığında hangi yönden gruplanacağını da belirler — buna **birleşme yönü**
denir. Çoğu ikili işleç (`+`, `-`, `*`, `/`) soldan sağa birleşir: `10 - 3 - 2` ifadesi
`(10 - 3) - 2` gibi gruplanır, `10 - (3 - 2)` gibi değil ve bu iki gruplama farklı
sonuçlar verir (`5` ile `9`). Atama işleci ise tam tersi yönde, sağdan sola birleşir:
`a = b = 5` ifadesi `a = (b = 5)` gibi gruplanır, önce `b`ye `5` atanır, sonra o atamanın
sonucu `a`ya atanır. Hem öncelik hem birleşme yönü, koşum hiç başlamadan, yalnız kaynaktaki
işleç dizilişine bakılarak derlemede çözülür.

## Kısa Devre: Hangi İşlecin Seçildiği İkinci İşleneni Etkiler

Mantıksal işleçler (`&&`, `||`) bir garanti taşır: sol işlenen sonucu belirlemeye
yetiyorsa, sağ işlenen hiç değerlendirilmez. Bitsel işleçler (`&`, `|`) aynı garantiyi
taşımaz — iki işlenen de her zaman değerlendirilir. Hangi garantinin geçerli olduğu,
kaynakta hangi işlecin yazıldığına bakılarak derlemede belirlenir.

```c
// kisadevre.c — hangi islecin secildigi ikinci islenenin calisip calismayacagini derlemede belirler
#include <stdio.h>

static int cagri_sayaci = 0;

static int yan_etkili(void) {
    cagri_sayaci++;
    return 1;
}

int main(void) {
    cagri_sayaci = 0;
    int ve_sonucu = (0 && yan_etkili());
    printf("%s %d\n", "ve isleci sonrasi cagri sayaci", cagri_sayaci);

    cagri_sayaci = 0;
    int bitsel_sonucu = (0 & yan_etkili());
    printf("%s %d\n", "bitsel islec sonrasi cagri sayaci", cagri_sayaci);

    (void)ve_sonucu;
    (void)bitsel_sonucu;
    return 0;
}
```

```
ve isleci sonrasi cagri sayaci 0
bitsel islec sonrasi cagri sayaci 1
```

**TS6.** İki çağrı da aynı `yan_etkili` işlevini, aynı `0` sol işleneniyle kullanıyor,
ama sonuç farklı: `&&` ile sol işlenen zaten yanlış olduğu için sağ işlenen hiç
çalıştırılmıyor ve `cagri_sayaci` sıfırda kalıyor; `&` ile ise sol işlenenin değeri
sonucu belirlemeye yetse de, işlecin kendisi böyle bir kısayolu tanımıyor ve
`yan_etkili` yine de çağrılıyor. Hangi garantinin uygulanacağı, koşum sırasında
`cagri_sayaci`nin gerçekten `0` mı `1` mi olacağını belirleyen bir karar — ama bu kararın
**kendisi**, hangi işlecin seçildiğine bakılarak, derleme sırasında sabitleniyor. İki
işlecin ikisi de aynı sol işlenenle aynı mantıksal sonucu (`0`) üretirdi; aralarındaki
fark sonuçta değil, ikinci işlenenin çalışıp çalışmayacağında.

Bu ayrım, `yan_etkili` gibi bir çağrının yalnızca **gerektiğinde** çalışmasını sağlamak
istendiğinde önem kazanıyor. Sol işlenen tek başına sonucu belirlemeye yetiyorsa (`&&`
için yanlış, `||` için doğru), kısa devre garantisi sağ tarafın hiç çalışmamasını
sağlıyor — bu, gereksiz bir işi atlamanın kaynakta yazılan tek satırla elde edilen bir
yoludur. Bitsel işleçler bu garantiyi taşımadığı için, iki işlenen de her koşulda
çalışır; bu yüzden bitsel işleçler mantıksal bir koşul için değil, gerçekten bit
düzeyinde bir birleştirme gerektiğinde tercih edilir.

## Bileşik Atama: Sol Tarafın Tipine Göre Dönüşüm

Bir bileşik atama işleci (`+=`, `|=` gibi) sonucu her zaman sol tarafın **bildirilen**
tipine dönüştürür — sağ tarafın tipi ne olursa olsun.

```c
// atama.c — bilesik atama sonucu sol tarafin tipine gore derlemede donusturulur
#include <stdio.h>

int main(void) {
    int tam_sayi = 5;
    tam_sayi += 2.7;
    printf("%s %d\n", "int uzerinde bilesik atama", tam_sayi);

    unsigned char bayrak = 0xF0;
    bayrak |= 0x0F;
    printf("%s %d\n", "unsigned char uzerinde bilesik atama", bayrak);

    int carpan = 6;
    carpan *= 2.5;
    printf("%s %d\n", "int uzerinde carpimsal atama", carpan);

    int sayac = 10;
    sayac -= 3;
    printf("%s %d\n", "int uzerinde cikarma atamasi", sayac);
    return 0;
}
```

```
int uzerinde bilesik atama 7
unsigned char uzerinde bilesik atama 255
int uzerinde carpimsal atama 15
int uzerinde cikarma atamasi 7
```

`tam_sayi += 2.7`, açılımıyla `tam_sayi = tam_sayi + 2.7` gibi çalışır: toplam önce
`double` genişliğinde hesaplanır (`5 + 2.7 = 7.7`), ama sonuç `tam_sayi`nın tipi `int`
olduğu için kesirli kısım atılarak `7`ye dönüştürülür. Bu dönüşüm sağ taraftaki `2.7`nin
değerine bakılarak değil, sol taraftaki `tam_sayi`nın bildirilen tipine bakılarak
uygulanıyor — sağ taraf `2.1` ya da `2.9` olsaydı da aynı kesme kuralı işlerdi.
`bayrak |= 0x0F` ise bitsel bir birleştirme: `0xF0` ile `0x0F`in bit düzeyinde birleşimi
`0xFF`, ondalıkla `255`. `carpan *= 2.5` aynı kuralı bir kez daha doğruluyor: `6 * 2.5 =
15.0`, `double` genişliğinde tam sayı değerli bir sonuç ve `carpan`ın tipi `int`
olduğu için hiç kesme kaybı olmadan `15`e dönüşüyor — kesmenin her zaman bir kayıp
anlamına gelmediğini, yalnız sonucun sol tarafın tipine **zorlandığını** gösteriyor.
`sayac -= 3` ise iki tarafın da zaten aynı tipte olduğu, dönüşümün görünmediği sıradan
durum. Dört örnekte de sonucun tipi sol tarafın bildirilen tipiyle sabitleniyor; bu,
atama işlecinin de tıpkı bölme işleci gibi tip odaklı çalıştığını gösteriyor.

## Sınırlayıcı Ölçüm

İşleç önceliği, kaynaktaki alt ifadelerin **hangi sırayla gruplanacağını** belirler, ama
bir ifadenin bütün alt bölümlerinin **hangi sırayla değerlendirileceğini** her zaman
belirlemez. `f(a, b)` gibi bir çağrıda `a` ile `b`nin hangisinin önce hesaplanacağı
belirtilmemiştir; eğer `a` ve `b` aynı değişkeni yan etkiyle değiştiriyorsa — örneğin
ikisi de aynı sayacı artırıyorsa — bu, standardın **tanımsız davranış** olarak
sınıflandırdığı bir durumdur: aynı nesne, aralarında bir sıralama noktası olmadan iki kez
değiştiriliyor. Bu kursun genel kuralınca böyle bir çağrı kod bloğunda **denenmiyor**.

Yanına konan tanımlı karşılık, virgül işlecidir: `,` ile ayrılan iki alt ifade her zaman
soldan sağa, aralarında tam bir sıralama noktasıyla değerlendirilir — sol taraf
tamamlanmadan sağ taraf başlamaz.

```c
// sinir.c — virgul isleci sirayi garanti eder, fonksiyon argumanlari garanti etmez
#include <stdio.h>

int main(void) {
    int i = 0;
    int son_deger = (i++, i++);
    printf("%s %d\n", "virgul isleciyle son deger", son_deger);
    printf("%s %d\n", "virgul isleciyle i", i);
    return 0;
}
```

```
virgul isleciyle son deger 1
virgul isleciyle i 2
```

`(i++, i++)` ifadesinde sol taraftaki `i++` önce tamamen çalışır: `i`nin eski değerini
(`0`) üretir ve `i`yi `1`e taşır — ama bu değer virgül işleci tarafından atılır. Ardından
sağ taraftaki `i++` çalışır: bu kez `i`nin (artık `1` olan) değerini üretir ve `i`yi
`2`ye taşır; ifadenin toplam sonucu sağ tarafın ürettiği değer, yani `1`. Sonuç
tamamen öngörülebilir ve her koşumda aynı: virgül işleci, fonksiyon çağrısının argüman
listesinin **vermediği** garantiyi tam olarak veriyor. Aynı `i++, i++` deseni bir
fonksiyon çağrısının iki bağımsız değişkeni olarak yazılsaydı (`f(i++, i++)` gibi),
derleyicinin argümanları hangi sırayla değerlendireceği belirtilmemiş olurdu ve aynı
`i`nin iki kez değiştirilmesi tanımsız davranışa düşerdi — bu ders o çağrıyı
denemiyor, yalnız virgül işlecinin garantili sırasını ölçüyor.

Aynı sınıftaki bir başka klasik örnek `i + i++` gibi bir ifadedir: toplama işlecinin iki
işleneni arasında da bir sıralama garantisi yoktur ve sol taraftaki `i` okunurken sağ
taraftaki `i++`nin bu okumadan önce mi sonra mı `i`yi değiştirdiği belirsizdir — aynı
nesne okunuyor ve değiştiriliyor, aralarında bir sıra garantisi olmadan. Bu da bu kursun
genel kuralınca koşturulmuyor. Buradaki ortak nokta, C'nin çoğu işlecinin işlenenleri
arasında **hiçbir sıralama garantisi vermediğidir** — sıralama yalnız birkaç özel yapı
için (virgül işleci, `&&`, `||`, `?:`in koşul kısmı) açıkça garanti edilir. Bir ifadede
aynı değişkeni birden fazla kez, en az biri değiştirerek kullanmak isteyen bir kaynak
yazarı, bu garantili yapılardan birine ya da ayrı ifadelere yaslanmak zorundadır;
aksi hâlde derleyicinin hangi sırayı seçeceği belirsiz kalır.

Bu derste ölçülen kararların tümü aynı soruya bağlanıyor: bir işlecin sonucu, işlenen
tiplerine ve kaynaktaki yapıya bakılarak **derlemede** mi belirleniyor, yoksa
işlenenlerin gerçek değerine bakılarak **koşumda** mı? Bölme, öncelik, kısa devre ve
bileşik atama için yanıt derleyiciydi — hangi işlemin çalışacağı ya da hangi sıranın
izleneceği, program hiç çalışmadan önce kaynaktan okunabiliyordu. Değerlendirme
sırasının tanımsız kaldığı durumlar ise bu kuralın istisnası değil, sınırı: derleyicinin
garanti **etmediği** yerde, kaynak yazarının kendi garantisini kurması gerekiyor.

## Özet

- Bir işlecin **hangi işlemi** yürüteceği, işlenenlerin çalışma zamanındaki değerine
  değil, kaynakta yazılan **tiplerine** bakılarak **derlemede** karara bağlanır — sınıf
  **derleyici**.
- İşleç önceliği, parantezsiz bir ifadenin hangi alt ifadelerin önce gruplanacağını
  kaynağın kendi yapısından, hiçbir veriye bakmadan belirler; birleşme yönü aynı
  önceliğe sahip işleçler yan yana yazıldığında hangi taraftan gruplanacağını verir.
- `&&` ve `||` kısa devre garantisi taşır, `&` ve `|` taşımaz; hangi garantinin
  geçerli olduğu, kaynakta hangi işlecin yazıldığına bakılarak derlemede sabitlenir.
- Bileşik atama işleçleri, sonucu her zaman sol tarafın bildirilen tipine dönüştürür —
  bu dönüşüm sağ tarafın değerine değil, sol tarafın tipine bakılarak yapılır.
- Fonksiyon çağrısı argümanlarının değerlendirme sırası belirtilmemiştir ve aynı
  değişkeni sıralama noktası olmadan iki kez değiştirmek tanımsız davranıştır; bu
  kursta koşturulmaz. Virgül işleci ise soldan sağa garantili bir sıra taşır ve
  tanımlı karşılık olarak koşturuldu.

## Sonraki Adım

Bu derste ölçülen kararların hepsi tek bir ifadenin sınırları içinde kaldı: bir işlecin
hangi işlemi yürüttüğü, hangi alt ifadenin önce gruplandığı, hangi işlenenin
değerlendirildiği. Bu kararların ortak özelliği, sonucu üreten **verinin** hiçbir zaman
kararı etkilememesiydi — yalnız kaynakta yazılan tipler ve yapı belirleyiciydi. Denetim
Akışı dersi bu zemine yeni bir soru ekliyor: bir programın hangi **dalı** izleyeceği
artık kaynakta değil, koşumda üretilen bir veriye bakılarak belirleniyor. Bu derste
`carpma_once` gibi bir sonucun hangi işlemden geldiği kaynaktan okunabiliyordu; sıradaki
derste bir dalın hangi kod yolunu izleyeceği, ancak program çalışıp veriyi ürettikten
sonra bilinebilecek — kaynağı okuyarak önceden söylenemeyecek.
