Tip Dönüşümü

Daha önceden atamada tip dönüşümünden ve bir veriyi istediğimiz veri tipinde depolayabileceğimizden bahsetmiştik. Bunlar tip dönüşümü ile ilgili ilk adımlar olarak kabul edilebilir. Bu sefer atama dışındaki durumlarda tip dönüşümünü inceleyeceğiz ve bir veriyi istediğimiz tipte depolamanın sonuçları üzerine örnekler vereceğiz.

Atama olmayan durumlarda tip dönüşümü ile neyi kastediyoruz? Diyelim ki kodumuzda aşağıdaki gibi bir satır olsun:

a = ( b + c ) * d;

Burada "( b + c ) * d" işleminin sonucu a'ya atanırken a'nın veri tipine dönüşecektir. Bu atamada tip dönüşümüdür. Peki b, c ve d değişkenleri aynı tipte değilseler "( b + c ) * d" işlemi nasıl yapılır? Burada işleme katılacak olan değişkenlerin değerleri belli bir hiyerarşi gözetilerek aynı veri tipine dönüştürülür ve işlem o şekilde yapılır. Bu kısımdaki tip dönüşümü yukarıda bahsettiğimiz, atama olmayan durumdaki tip dönüşümüdür.

İlk önce tüm char ve short int tipindeki veriler int tipine dönüştürülür. Devamında her işlemde işleme katılan verilerden düşük tipte olan yüksek tipte olana dönüştürülür. Peki bir veri tipinin diğerinden yüksek mi alçak mı olduğunu ne belirler? Burada en yüksekten en düşüğe aşağıdaki hiyerarşi kullanılır:

long double
double
float
unsigned long int
long int
unsigned int
int

Buradaki özel bir durum şudur; eğer işleme katılanlardan birisi unsigned int ve diğeri de long int ise ve unsigned int tipindeki değer long int veri tipinin sınırları dışında kalıyorsa her iki veri de unsigned long int'e dönüşür.

C99 bu tabloda float ile unsigned long int arasına sırasıyla unsigned long long int ve long long int tiplerini ekler.

Tip dönüşümünde genel olarak yüksek olan veri tipinin sınırları alçak olanı kapsar. Fakat unsigned int ve unsigned long int'e doğru olan dönüşümlerde durum farklı olabilir. Çünkü unsigned ile modifiye edilen veri tipleri negatif değerleri ifade edemez. Bu nedenle bu dönüşümlerin olabileceği yerlerde dikkatli olunmalıdır.

Konuyla alakalı hemen bir örnek verelim:

#include <stdio.h>

int main(void){
    int a=-2;
    unsigned long int b=2;
    double c=-3.0;
    double d=(a*b)+c;
    printf("%f",d);
    return 0;
}

Yukarıdaki işlemin çıktısı 4294967289.000000 olmaktadır. Halbuki yukarıdaki hesabı elle yapmış olsaydık; (-2*2)+(-3)=-7 sonucunu elde ederdik.

Buradaki sıkıntı şundan kaynaklanmaktadır:

ilk olarak "a*b" işlemine long int olarak -2 ve unsigned long int olarak 2 katılmaktadır. İkisinin de bitlerde tutuluşuna bakalım:

a: 11111111 11111111 11111111 11111110
b: 00000000 00000000 00000000 00000010

unsigned int'e dönüştürüldüğünde negatif olma özelliğini kaybetmek zorundadır. Yukarıda depolanan bitlerin unsigned int karşılığı 4294967294'tür. Bunun 2 ile çarpımı da 32 biti aşacaktır ve kalan bitler aşağıdaki sayıyı oluşturacaktır:

11111111 11111111 11111111 11111100

Bu sayının karşılığı da 4294967292'dir. Bu sayı c ile toplanırken double tipine dönüştürülecek ve toplamın sonucu 4294967289.000000 çıkacaktır.

Görüldüğü gibi tip dönüşümü hatalı sonuçlar elde etmeye sebep olabilmektedir. Bu nedenle dikkatli olunmalıdır.

Sayıların yanına harflerin konması durumuna bir örnek verelim. Misalen kullandığımız işlemci 16 bitlik olsun. Şimdi aşağıdaki koda bakalım:

#include <stdio.h>

int main(void){
    unsigned int a=2;
    double b=-3.0;
    double c=(a*-2)+b;
    printf("%f",c);
    return 0;
}

Bu kod da yanlış sonuç verecektir. Fakat işlemci 16 bit ise "a*-2" işlemi yerine "a*-2L" işlemini yaptırmak sorunu çözecektir. Çünkü 16 bitlik işlemcide unsigned int olan a long int'e dönüştürülecek ve işlemin sonucu doğru çıkacaktır. 32 bitlik işlemcide de aradaki fark yukarıdaki kod ile aşağıdaki karşılaştırılarak görülebilir.

#include <stdio.h>

int main(void){
    unsigned int a=2;
    double b=-3.0;
    double c=(a*-2LL)+b;
    printf("%f",c);
    return 0;
}

32 bitlik işlemcide üstteki kodda "a*-2" işleminde int olan -2 unsigned int'e dönüştürülmüştür. Negatif değerler unsigned int'te ifade edilemediği için hata olmuştur. Aşağıdaki kodda ise unsigned int olan a'nın değeri, yani 2, long long int'e dönüştürülmüş ve herhangi bir hata oluşmamıştır.

Bunun dışında bir sınıf belirtilerek tüm ifadenin o şekilde işleme tabi tutulması sağlanabilir. Bu şu kalıpla yapılır:

(tip) ifade

Örnek koda bakalım:

#include <stdio.h>

int main(void){
    int a=10;
    float b=a/3;
    printf("%f",b);
    return 0;
}

Burada çıktımız 3.000000 olacaktır. Çünkü a ve 3 int tipindedir. Önce işlem yapılacak ve küsuratlı kısım atılarak çıktı olarak int tipinde bir veri elde edilecektir. Daha sonra bu değer float'a dönüştürülecektir. Bu işlemi farklı şekilde yapalım:

#include <stdio.h>

int main(void){
    int a=10;
    float b=(float)a/3;
    printf("%f",b);
    return 0;
}

Bu durumda çıktımız 3.333333 olacaktır. Çünkü a'nın değerinin ve 3'ün float'a dönüştürülmesi ve çıktı olarak da float elde edilmesi sağlanmıştır. Bunu sağlayan, işlemden önce yazılan (float) ifadesidir.




Diğer İşlemler <<<<< Temel C >>>>> Seçme Komutları