UNION

Şimdiye kadar, her değişkene ana bellekte belirli bir yer tahsis edildiğini ve tahsis edilen o yere başka birisinin değerinin giremeyeceğini söyledik. Temel veri türleri ve onların türevlerine ek olarak tanımladığımız diziler(array) ve yapılar (struct) bir programda gerekseme duyacağımız işlerin büyük bir çoğunluğunu çözmeye yetecek zenginliktedir. Ancak,sık olmasa bile, bazı durumlarda bir bellek alanına, farkı zamanlarda, farklı değişkenlerden istenen birisinin değerini girebilmeyi isteriz. C dili bu gereksemeye bir çözüm getirmek için, bize union adlı bir veri türü daha sunmaktadır...

union, bileşenlerine ortak bir bellek alanını kullandıran bir veri türüdür.

Union'un tanımı ve kullanımı, yapı'nın (struct) tanımına ve kullanımına benzerdir. Union bildirimi için sözdizimi ţöyledir:

union [ad] {

.........

değişkenlerin bildirgesi

.........

} değişken_adı,pointer_adı;

Bildirgede union anahtar sözcüğü gereklidir; ama union’a ad vermek isteğe bağlıdır. Değişkenlerin bildirgesi, { } bloku içinde yer alır. Bu bildirgede, C dilindeki değişken bildirimi kuralları uygulanır. { } bloku içinde yer alan değişkenlere union'un bileşenleri diyeceğiz.

Union'un { } blokundan hemen sonra, unionu temsil edecek değişkenlerin adları ile o türden bir değişkeni işaret edecek pointerler yazılabilir. istenirse, yapılarda olduğu gibi, union adına gönderme yoluyla da değişken tanımı yapılabilir.

Aradaki tek fark şudur: Yapının her bileşenine ana bellekte ona yetecek kadar bir yer ayrılmasına karşılık, union için bir tek yer ayrılır. Bu yer, union'u oluşturan değişkenlerin (ana bellekte kapladığı alan bakımından) en büyüğünü içerebilecek uzunluktadır. örneğin,

union birlik {

char h;

int t; (1)

float f;

} x, *p;

tanımı, birlik adlı union tanımlar. x değişkeni birlik adlı unionu temsil edecektir. p pointeri birlik türünden bir unionu işaret edecektir. Aynı bildirimi aşağıdaki biçiminde de yapabiliriz.

union birlik {

char h;

int t;

float f; (2)

}

union birlik x, *p;

Union'un { } bloku içinde yer alan h,t,f değişkenleri arasında en büyük bellek olanı gerektiren değişken float türünden olan f adlı değişkendir. Dolayısıyla, derleyici, birlik adlı unionu'u temsil eden x değişkenine ana bellekte float veri türünün sığabileceği büyüklükte bir tek yer tahsis eder. PC'lerde bu yer 4 byte uzunluktadır.

Şimdi aşağıdaki şema ile değişik durumları inceleyelim: Her bir küçük kutu 1 byte uzunlukta bir bellek alanını temsil etsin.

x değişkeninin hiç bir bileşenine henüz adama yapılmamışken bellekteki durum şöyledir:

X

x için ayrılan bu yere, herhangi bir anda, x'in bileşenleri olan h,t,f bileşenlerinden istenen bir tanesi için değer girilebilir. Aynı anda birden çok bileşen için değer girilemez.

Eğer bu yere h bileşeni için değer girilirse, 1 byte uzunluktaki bir parçası dolacak, diğer kısımlar boş kalacaktır.

X

x için ayrılan bu yere, t bileşeni için değer girilirse, 2 byte uzunluktaki bir parçası dolacak, diğer kısımlar boş kalacaktır:

X

Eğer ayrılan bu yere f bileşeni için değer girilirse, 4 byte uzunluktaki bütün bellek alanı tamamen dolacaktır:

X

Programcı, hangi anda hangi bileşen değerinin x 'in yerinde olduğunu bilmek zorundadır. Bunu bilmezse, program ciddi yanlışlar yapabilir. Örneğin, x için ayrılan yerde f bileşeni için girilen bir değer varken, h bileşeni için değer okutulacak olursa, sağdaki ilk kutuda yer alan veri okunacak, öteki üç kutudaki veriler ihmal edilecektir.

Union'un Bileţenlerine Eriţim

Union'un bileşenlerine erişim yöntemleri, yapının bileşenlerine erişim yöntemleriyle aynıdır. O halde, dolaysız (direct) ve dolaylı (indirect) yöntemlerle erişim yapılabilir.

Dolaysız (direct) erişim yöntemi

Bunun için sözdizimi ţöyledir:

union'u_temsil_eden_değişkenin_adı.bileşenin_adı

Bu öge, sözkonusu bileşeni temsil eden bir değişkendir. Dolayısıyla türünün girebildiği bütün işlemlere girer; aynı kurallara uyar. Örneğin, yukarıdaki union için

x.h

x.t (3)

x.f

ögeleri, x değişkeni ile temsil edilen birlik adlı unionun h,t,f bileşenlerini temsil eden değişkenlerdir.

Dolaylı (indirect) erişim yöntemi

Union'u temsil eden bir değişkeni işaret eden bir pointer tanımlanabilir. Bu pointer yardımıyla union'un bileşenlerine erişebiliriz. Bunun için sözdizimi şöyledir:

pointerin_adı->bileşenin_adı

Bu öğe, sözkonusu bileşeni temsil eden bir değişkendir. Dolayısıyla türünün girebildiği bütün işlemlere girer; aynı kurallara uyar. Bu yönteme, dolaylı erişim yöntemi diyoruz. Örneğin, (1) ya da (2) bildiriminden sonra, uygun bir blok içinde

p = &x; (4)

adaması yapılmış olsun. Bu durumda

p->h

p->t (5)

p->f

öğeleri, p pointerinin işaret etteği ve x değişkeni ile temsil edilen birlik adlı unionun h,t,f bileşenlerini temsil eden değişkenlerdir. Dolayasıyla, bu değişkenler (3) ile belirlenen değişkenlere denktir.

Adama ve aktarma iţlemleri

Union için adama ve aktarma işlemleri yapılardaki adama ve aktarma işlemleri gibidir. O halde, yukarıdaki bildirimler altında

x.h ='A'; (6)

deyimi, dolaysız yöntemle,h bileşenine A değerini adar. Aynı işi dolaylı yöntemle yapmak için

p->h='A'; (7)

diyimini kullanacağız. Eğer ch1 ve ch2 char türünden iki değişken ise, h bileşeni ile aralarında aktarma işlemleri yapılabilir. Bunun için, dolaysız yöntemde

ch1 = x.h;

x.h = ch2 (8)

deyimleri kullanılabilir. Aynı işi dolaylı yöntemle yapmak için,

ch =p->h;

p->h =ch2; (9)

deyimleri kullanılabilir. Buradaki ilk iki deyimin yaptığı iş, son iki deyimin yaptığı işe denktir.

 

Union ve yapı

Bir union içinde bir yapı ya da bir yapı içinde bir union tanımlanabilir.

Union içinde bir yapı tanımlayarak, bir tam sayının ana bellekteki yerleşimini belirleyebiliriz. Bunun için tamsayıların ana bellekte nasıl saklandığını anımsamak gerekir.

Bilindiği gibi, tamsayılar ana bellekte 2 byte uzunlukta bir bellek alanına yerleşir. Bunlardan sağda olanıma alt bellek alanı (low order bits), solda olanına da üst bellek alanı (high order bits) denilir.

Üst bellek alanı Alt bellek alanı

 

 

Örneğin,28 sayısının ikilik sayıtlama dizgesindeki yazılışı

00011100

biçiminde olduğundan, bu sayının ana bellekteki yerleşimi şöyle olacaktır.

šst bellek alanı Alt bellek alanı

0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0

Bu sayının onaltılık(hexadecimal) sayıtlama dizgesindeki yazılışı ise

00 1C

biçimindedir. Şimdi bir tamsayı içerebilecek büyüklükte bir union tanımlayalım. Sonra, bu union içine birer byte uzunlukta iki bileşenli bir yapı yerleştirelim.

Örnek 1

#include <stdio.h>

union ikiharf {

int t;

struct {

char h1;

char h2;

} harf;

} tam;

main() {

int n;

printf("Bir tamsayı giriniz.\n");

scanf("%d",=n;

tam.t = n;

printf("Bellekte saklanan int %6d dir.\n",tam.t);

printf("Alt bellekte saklanan int parçası %x dir.\n",tam.harf.h1);

printf("šst bellekte saklanan int parçası %x dir.\n",tam.harf.h2);

}

Klavyeden girilen sayı 28 ise, bu programın çıktısı şunlar olacaktır:

Bellekte saklanan int 28 dir.

alt bellekte saklanan int parçası 1C dir

šst bellekte saklanan int parçası 00 dir.

Şimdi bu programı çözümleyelim:

Bildirge iki harf adlı bir union tanımlamaktadır. tam adlı değişken unionu temsil etmektedir. ikiharf unionu içinde bir yapı yuvalanmıştır. Bu yapıya ad verilmemiştir. Yapıyı temsil eden değişkenin adı harf'dir. Bu duruma göre, unionun bileşenlerini temsil eden değişkenler şunlardır.

tam.t

tam.harf.h1

tam.harf.h2

Programdaki

tam.t = n;

deyimi, scanf() fonksiyonunun okuduğu tamsayıyı, unionu temsil eden tam adlı değişkene ayrılan iki byte uzunluktaki bellek alanına yerleştirir.

Bu adamadan sonra, derleyici, buradan okunacak verinin hangi bileşene ait olduğunu denetlemez. Bu konu programcının sorumluluğundadır.

Unionun ikinci bileşeni bir yapıdır. Bu yapının da iki bileşeni vardır. Bu bileşenlerin her birisi char türünden olduğundan, derleyici, onlara 1 er byte uzunlukta ayrı yerler tahsis edecektir. Bu yerler, uniona tahsis edilen 2 byte uzunluktaki yerin dışına çıkamaz. Öte yandan, yapının bileşenlerine tahsis edilen yerler, yapıdaki bildirimin sırasına uyar. Öyleyse, yapının ilk bileşenini temsil eden tam.harf.h1 değişkenine alt bellek alanı tahsis edilir. İkinci bileşenini temsil eden tam.harf.h2 değişkenine ise üst bellek alanı tahsis edilir.

O halde, programımızın son iki satırı alt bellek alanı ile, üst bellek alanına yerleşmiş olan verileri ekrana yazacaktır. %x dönüştürücüsü kullanıldığı için, tabloda görülen

Üst bellek alanı Alt bellek alanı

0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0

alt bellek alanındaki sayı 1C olarak, üst bellek alanındaki sayı 00 olarak çıkar.

Aşağıdaki örnek bir yapı içinde bir unionun yuvalanmasını göstermektedir. Programı satır satır çözümleyiniz.

Örnek 2

struct deneme {

int i;

double s;

union {

int a;

char b;

doumle c;

}s2;

} x;