---
title: 'Yapılar, Birlikler ve Numaralandırmalar'
source: 'https://academia.sh/tr/kurslar/c-temelleri/yapilar-birlikler-ve-numaralandirmalar'
course: 'C Temelleri'
language: tr
updated: '2026-10-21T05:02:45+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Yapı alanlarının derlemede yerleştiğini ve atamanın bütün alanları kopyaladığını ölçer'
    - 'Bir birliğin aynı belleği paylaştığını etiketli okumayla güvenle gösterir'
    - 'Numaralandırma sabitlerinin derleme zamanı sabiti olduğunu örnekle doğrular'
---

# Yapılar, Birlikler ve Numaralandırmalar

Yapı alanlarının derlemede yerleşmesi, bir birliğin aynı belleği paylaşması ve numaralandırma sabitlerinin derleme zamanı sabiti olması; birlikte hangi alanın geçerli olduğunu dilin izlemediğinin bir etiket alanıyla gösterilmesi.

Diziler ve Dizgiler dersi, aynı tipten değerlerin bir dizi içinde nasıl sıralandığını
ölçtü. Bu ders farklı tiplerden değerlerin tek bir ad altında nasıl toplandığını ölçüyor:
bir **yapı** farklı tipleri yan yana yerleştirir, bir **birlik** aynı belleği farklı
yorumlarla paylaştırır, bir **numaralandırma** ise adlandırılmış sabitler üretir — üçü de
kaynakta yazılan bildirimden, derlemede karara bağlanan düzenekler.

Programlama Temelleri kursu (M01/K02) kayıt benzeri veri gruplamasını Python'la zaten
kurmuştu; orada alanlar bir sözlük ya da nesne içinde, çalışma zamanında eklenip
çıkarılabilen adlardı. C'nin karşılığı burada ölçülüyor: bir yapının hangi alanları
taşıyacağı, bu alanların bellekte hangi sırayla duracağı ve bir numaralandırma sabitinin
değeri — hepsi kaynakta yazılan bildirimden, program hiç çalışmadan derlemede
sabitleniyor. Bu, kursun ölçü ekseninin son durağı: bir kaynağın dört aşamadan geçerek
programa dönüştüğü **C'nin Konumu** dersinde açılan soru, burada üç yeni düzeneğin
hangi aşamada karara bağlandığını sorarak kapanıyor.

## Yapı: Alanların Derlemede Yerleşmesi

Bir yapı bildirimi, her alanın adını ve tipini kaynakta sabitler; bu bildirimden sonra o
yapı tipindeki her değişken aynı alan düzenini taşır. Diziler ve Dizgiler dersinde
ölçülen bir dizi, aynı tipten değerleri sıralarken, bir yapı farklı tiplerden değerleri
tek bir ad altında toplar — bir noktanın `x` ve `y` koordinatları gibi, birlikte anlam
taşıyan ama farklı olabilecek tiplerden değerler. Bir yapı değişkenini bir başkasına
atamak, bütün alanları tek seferde kopyalar.

```c
// yapi.c — yapinin alanlari derlemede yerlesir, atama butun alanlari kopyalar
#include <stdio.h>

struct Nokta {
    int x;
    int y;
};

int main(void) {
    struct Nokta a = {3, 4};
    struct Nokta b = a;
    b.x = 99;

    printf("%s %d\n", "a.x", a.x);
    printf("%s %d\n", "a.y", a.y);
    printf("%s %d\n", "b.x", b.x);
    printf("%s %d\n", "b.y", b.y);
    return 0;
}
```

```
a.x 3
a.y 4
b.x 99
b.y 4
```

**TS12.** `struct Nokta` bildirimi, her `Nokta` değişkeninin bir `x` ve bir `y` alanı
taşıyacağını, bu alanların adlarını ve tiplerini derlemede sabitliyor — bu yapı hangi
alanları taşıyacağını koşumda değil, kaynakta belirliyor. `b = a` ataması, `a`nın her iki
alanını da `b`ye kopyalıyor; ardından `b.x`e yapılan değişiklik yalnız `b`nin kendi
kopyasını etkiliyor, `a.x` hâlâ `3`. Bu, önceki derste ölçülen parametre kopyalama
kuralının bir yapı için nasıl işlediğini gösteriyor: bir yapı değişkeni bir başkasına
atandığında ya da bir işleve geçirildiğinde, aktarılan şey bütün alanların bir
**kopyasıdır** — dizinin aksine, yapı işleve geçtiğinde ilk elemanının adresine
dönüşmez, tüm alanlarıyla kopyalanır.

Alanların bellekteki sırası da kaynaktaki bildirim sırasıyla belirlenir: `struct
Nokta`nın `x` alanı her zaman `y`den önce yerleşir, çünkü bildirimde önce yazılan
alan önce gelir. Bir yapı, kendi içine başka bir yapıyı da alan bulundurabilir —
`struct Nokta` alanları taşıyan bir `struct Cizgi { struct Nokta bas; struct Nokta son;
};` gibi — ve bu iç içe geçme de aynı kuralı katmanlı biçimde sürdürür: her iç yapının
kendi alanları, dış yapının kendi alanı içinde, yine bildirim sırasına göre yerleşir. Bu yerleşim kararı, tıpkı bir dizinin eleman sayısı gibi, program hiç
çalışmadan derleyici tarafından sabitlenir — hangi alanın hangi adreste durduğu
koşumdaki veriye hiç bakılmadan, yalnız bildirimin kendisinden belirlenir. Bu kursta
hiçbir gerçek adres ya da bayt uzaklığı basılmıyor, ama bildirim sırasının bir sonucu
olması, yapı tanımının neden hem verinin **anlamını** hem bellekteki **düzenini**
aynı anda belirlediğini gösteriyor.

## Birlik: Aynı Belleğin Paylaşılması

Bir birlik, birden çok alanı **aynı** bellek alanında tanımlar — her alan aynı adrese
karşılık gelir, farklı bir tip yorumuyla. Birliğin kendisi hangi alanın "geçerli"
olduğunu izlemez; bu bilgi, bir **etiket** alanıyla ayrıca taşınmalıdır.

```c
// birlik.c — birligin ayni alani paylasmasi, etiketli okumayla guvenli kullanilir
#include <stdio.h>

enum Tur { TAM_SAYI, ONDALIK };

struct EtiketliDeger {
    enum Tur tur;
    union {
        int tam;
        float ondalikli;
    } deger;
};

static struct EtiketliDeger tam_sayi_uret(int v) {
    struct EtiketliDeger e;
    e.tur = TAM_SAYI;
    e.deger.tam = v;
    return e;
}

static struct EtiketliDeger ondalik_uret(float v) {
    struct EtiketliDeger e;
    e.tur = ONDALIK;
    e.deger.ondalikli = v;
    return e;
}

static void yazdir(struct EtiketliDeger e) {
    if (e.tur == TAM_SAYI) {
        printf("%s %d\n", "tam sayi olarak okundu", e.deger.tam);
    } else {
        printf("%s %.2f\n", "ondalik olarak okundu", e.deger.ondalikli);
    }
}

int main(void) {
    struct EtiketliDeger bir = tam_sayi_uret(42);
    struct EtiketliDeger iki = ondalik_uret(3.5f);
    yazdir(bir);
    yazdir(iki);
    return 0;
}
```

```
tam sayi olarak okundu 42
ondalik olarak okundu 3.50
```

**TS13.** `union` içindeki `tam` ile `ondalikli`, aynı bellek alanını paylaşıyor —
biri yazıldığında öbürünün eski değeri anlamsız hâle geliyor, çünkü ikisi aynı baytları
farklı bir tip merceğinden okuyor. `tam_sayi_uret` yalnız `deger.tam`ı yazıyor,
`ondalik_uret` yalnız `deger.ondalikli`yi; `yazdir` de her zaman `tur` alanına bakıp
**hangi yorumun geçerli olduğunu** ondan öğreniyor ve yalnız o alanı okuyor. Bu disiplin
sayesinde ders hiçbir zaman "yazılmayan" alanı okumuyor — `bir` için hep `tam`, `iki`
için hep `ondalikli` okunuyor. `union EtiketliDeger` (`deger` alanı) kendi başına hangi
üyenin son yazılan olduğunu **bilmez**; bu bilgiyi taşımak `tur` alanının ve o alanı
doğru tutmak kaynak yazarının işi.

Bir birliğin kaplayacağı yer de derlemede sabitlenir: standardın koyduğu ölçü, birliğin
**en büyük alanını** taşımaya yetecek kadar yer ayrılmasıdır — çünkü herhangi bir anda
herhangi bir alan yazılabilir olmalı. Bu kursta hiçbir gerçek boyut basılmadığı için bu
ders bunu ölçmüyor, ama iki bildirimin büyüme biçimi arasındaki farkı belirtmek gerekir:
yapı alanları arka arkaya dizer, birlik üst üste bindirir. Bu yüzden birliğe en
büyüğünden küçük bir alan eklemek toplam yeri genellikle büyütmez; yapıya eklemek ise
alan mevcut dolgunun içine sığmadıkça büyütür. İkisinde de son sözü hizalama söyler:
standart hem yapının hem birliğin sonunda adsız dolgu bulunabileceğini belirtir, bu
yüzden toplam yer alanların boyutlarından doğrudan okunmaz.

## Numaralandırma: Derleme Zamanı Sabiti

Bir numaralandırma bildirimi, adlandırılmış tam sayı sabitleri üretir; bu sabitler
kaynakta yazılan sabit ifadelerin kullanılabileceği her yerde kullanılabilir — örneğin
bir dizinin uzunluğunu belirlemek için.

```c
// asama.c — numaralandirma sabiti (kesit), derleme zamani sabiti olarak kullanilir
#include <stdio.h>

enum Renk { KIRMIZI = 1, YESIL = 2, MAVI = 4 };

int main(void) {
    printf("%s %d\n", "numaralandirma sabiti", (int)MAVI);

    int renkler[MAVI];
    printf("%s %d\n", "sabitle olusturulan dizi eleman sayisi",
           (int)(sizeof renkler / sizeof renkler[0]));
    return 0;
}
```

```
numaralandirma sabiti 4
sabitle olusturulan dizi eleman sayisi 4
```

`MAVI` değeri, `enum Renk` bildiriminde yazılan `4` sabitinden geliyor ve bu değer
program hiç çalışmadan bellidir. `int renkler[MAVI];` bildirimi bunu doğruluyor: `MAVI`,
Diziler ve Dizgiler dersinde ölçülen sabit ifade katlamasının kabul ettiği türden bir
ifade — bir değişken ya da bir işlev çağrısı olsaydı, dizinin boyutu derlemede
belirlenemezdi. `renkler` dizisinin eleman sayısı, hiçbir gerçek boyut basılmadan, yine
`sizeof` oranıyla ölçülüyor ve `4` çıkıyor — `MAVI` ile birebir aynı sayı, çünkü ikisi de
aynı derleme zamanı sabitinden türüyor.

`enum Renk` bildirimindeki `KIRMIZI = 1, YESIL = 2, MAVI = 4` gibi açık değerler
zorunlu değildir; bir numaralandırma, hiçbir değer yazılmadan da bildirilebilir ve bu
durumda ilk ad `0`dan başlayarak, her ad bir öncekinden bir fazla değer alır. Buradaki
bildirim değerleri açıkça yazıyor, çünkü `KIRMIZI`, `YESIL` ve `MAVI` ayrı bit
konumlarını (`1`, `2`, `4`) temsil ediyor ve bu, renklerin bir bit maskesiyle
birleştirilebilmesini sağlıyor — `KIRMIZI | MAVI` gibi bir ifade, iki rengi aynı anda
temsil eden `5` değerini üretebilir. Bu kullanım da yine derlemede sabitlenen bir
özellik: hangi sabitin hangi bit konumuna karşılık geldiği, kaynakta yazılan `=`
işaretinden geliyor, koşumdaki hiçbir veriye bakılmıyor.

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

Bir birlik, hangi alanının en son yazıldığını **kendi başına** izlemez — bu bilgiyi dil
değil, kaynak yazarı taşımak zorundadır. Yukarıdaki `EtiketliDeger` yapısı bunu bir
etiket alanıyla çözüyor: `tur`, `deger`in hangi üyesinin geçerli olduğunu söylüyor ve
`yazdir` her zaman önce `tur`e bakıyor.

Eğer bu disiplin bırakılsaydı — `yazdir` `tur`e hiç bakmadan, örneğin her zaman
`deger.ondalikli`yi okusaydı — `bir` değişkeni için (ki `tam_sayi_uret` yalnız
`deger.tam`ı yazmıştı) okunan bayt örüntüsü bir `int` olarak yazılmış, bir `float`
olarak okunmuş olurdu. Bu, birliğin garanti ettiği tek şeyin **aynı adresi paylaşmak**
olduğunu, hangi tip yorumunun **anlamlı** olduğunu garanti etmediğini gösteriyor —
yorum uyuşmazlığının sonucu belirsiz bir bit örüntüsüdür ve bu kursun genel kuralınca
kod bloğunda **denenmiyor**. Yanına konan tanımlı karşılık, yukarıdaki etiketli
okumanın kendisi: her okuma, o birliğe en son hangi üyenin yazıldığını bağımsız bir
alandan (`tur`) öğrenip yalnız o üyeyi okuyor ve bu ölçüm üç kez koşturulduğunda da
aynı iki satırı üretiyor.

Etiketli okumanın çalışması için, etiketin **her zaman** ilgili yazmayla birlikte
güncellenmesi gerekiyor — `tam_sayi_uret` ve `ondalik_uret` işlevlerinin ikisi de,
kendi alanlarını yazmadan önce `tur`ü ayarlıyor. Eğer bir üçüncü işlev `deger.tam`ı
yazıp `tur`ü güncellemeyi unutsaydı, o değişkeni okuyan `yazdir` hâlâ eski `tur`
değerine bakar ve yanlış üyeyi okurdu — birlik kendi başına bu tutarsızlığı ne
üretebilir ne engelleyebilir, çünkü birliğin kendisi yalnız bellek paylaşımını sağlıyor,
etiketle senkron kalmayı değil. Bu, C'nin birlik düzeneğinin bilinçli bir tasarım
kararını yansıtıyor: dil, alan seçimini izlemenin **maliyetini** üstlenmiyor — her
yazmada hangi alanın aktif olduğunu ayrıca kaydetmiyor — ve bu sorumluluğu, tıpkı dizi
uzunluğu bilgisinde olduğu gibi, tamamen kaynak yazarına bırakıyor.

Bu, yapı ile birliğin birbirini tamamlayan iki düzenek olduğunu da gösteriyor: yapı her
alan için **ayrı** bellek ayırıp hepsini aynı anda geçerli kılarken, birlik tek bir
bellek alanını **paylaştırıp** yalnız birini geçerli kılıyor. `EtiketliDeger`, bu ikisini
birleştiriyor — dıştaki yapı hem etiketi hem paylaşılan alanı taşıyor ve etiket alanı
sayesinde birliğin izlemediği bilgi yapı düzeyinde tutulmuş oluyor.

Bu birleşim, C'de "etiketli birlik" (tagged union) diye anılan yaygın bir kalıbın
temelini oluşturuyor: birden çok olası biçimden yalnız birini taşıyan bir değeri
modellemek isteyen bir kaynak yazarı, bu üç düzeneği — yapı, birlik ve numaralandırma —
birlikte kullanır. Numaralandırma, hangi biçimin geçerli olduğunu adlandırılmış
sabitlerle ifade eder; birlik, o biçimlerin ortak bir bellek alanını paylaşmasını
sağlar; yapı, ikisini bir arada, tek bir değer olarak taşır. Bu derste ölçülen üç
düzenek, bu yüzden birbirinden bağımsız üç konu değil, aynı kalıbın üç bileşeni.

## Özet

- Bir yapının alanları, adları ve tipleriyle birlikte **derlemede** sabitlenir; bir
  yapı değişkeni bir başkasına atandığında bütün alanlar tek seferde kopyalanır.
- Bir birlik, birden çok alanı aynı bellek adresinde tanımlar; hangi alanın son
  yazılan olduğunu dil izlemez, bu bilgiyi kaynak yazarı ayrıca (bir etiket alanıyla)
  taşımak zorundadır.
- Numaralandırma sabitleri (`enum Renk` içindeki `MAVI` gibi) derleme zamanı
  sabitleridir; bir dizinin uzunluğunu belirlemek gibi sabit ifade gerektiren her
  yerde kullanılabilirler — sınıf **derleyici**.
- Bir birlikte yazılmayan bir üyeyi okumak (etiketsiz, yanlış tip varsayımıyla)
  baytları başka bir tip olarak yeniden yorumlar; C bunu yasaklamaz ama son yazılan
  üyeye karşılık gelmeyen baytların değeri **belirtilmemiştir** ve okunan örüntü bir
  tuzak temsiliyse davranış tanımsız olur. Bu kursta koşturulmaz; tanımlı karşılık,
  etiketli okumadır.
- Yapı her alanı ayrı bellekte tutup hepsini birden geçerli kılarken, birlik tek bir
  bellek alanını paylaştırıp yalnız birini geçerli kılar — ikisi birbirini tamamlayan
  iki düzenek.
- Numaralandırma, birlik ve yapı bir arada kullanıldığında "etiketli birlik" kalıbını
  kurar: numaralandırma hangi biçimin geçerli olduğunu adlandırır, birlik biçimlerin
  belleğini paylaştırır, yapı ikisini tek bir değerde birleştirir.

## Sonraki Adım

Bu konuda ölçülen her karar, bir programın **tek bir koşumu** içinde kaldı: bir tipin
aralığı, bir adın kapsamı, bir işlecin seçimi, bir dalın izlediği yol, bir çağrının
bağlandığı gövde, bir dizinin uzunluğu, bir birliğin geçerli alanı — hepsi ya kaynaktan
ya da o koşumun kendi verisinden okunabiliyordu. Girdi/Çıktı dersi bu zemine son bir
soru ekliyor: bir programın **dışarıdan** aldığı ya da dışarıya yazdığı veri, hangi
aşamada yorumlanıyor? Bir biçim dizesindeki (`format string`) her yer tutucu, karşılık
gelen bağımsız değişkenin tipiyle uyuşmak zorunda, ama bu uyuşmayı derleyici yalnız
belirli koşullarda yakalayabiliyor — dilin kendisi bunu garanti etmiyor. Bu derste
ölçülen `EtiketliDeger` örneğinde etiketi doğru tutmak kaynak yazarının işiydi; sıradaki
derste biçim dizesini argümanlarla uyumlu tutmak da aynı şekilde kaynak yazarının
sorumluluğunda olacak.

Bu konuda ölçülen yedi ders, dört sınıfın (ön işlemci, derleyici, bağlayıcı, koşum) her
birine en az bir kez uğradı: Veri Tipleri ve İşleçler derleyicide, Denetim Akışı
koşumda, Değişkenler ile Fonksiyonlar bağlayıcıda, Diziler ve Dizgiler ikisinde birden
ve bu ders yine derleyicide durdu. Kapanış dersi, bu yedi dersin ölçtüğü kararları tek
bir tabloda topluyor ve girdi çıktının kendi payını — biçim dizelerinin koşumda
yorumlanmasını — bu tabloya ekliyor.
