C# Göstericiler,Ön İşlemciler,Temel Giriş Çıkış İşlemleri

C# Göstericiler,Ön İşlemciler,Temel Giriş Çıkış İşlemleri

C#’ta Gösterici(Pointer) Kullanımı ve Emniyetsiz(unsafe) Kod

  • Her ne kadar .NET platformunda bellek yönetimi gereksiz bilgi toplayıcısı(Garbage collector) dediğimiz mekanizma ile otomatik olarak sağlansa da bazen direk belleğe erişmemiz gerekebilir.
  • Bu durumda işaretçiler(pointer) kullanılır. .NET’in alt yapısında pointerlar sıklıkla kullanılırken, pointer kullanımının programdaki görünmeyen hatalara sıkça yol açtığından dolayı programcılar için gizlenmiştir.
  • pointer kullanımı birçok sıkıntıya yol açmaktadır. Bunlardan en önemlileri kullanım zorluğu ve bulunması zor hatalara yol açabilmesidir.
  • C# ‘ta pointer kullanılacağı zaman kod blokları unsafe anahtar kelimesi kullanılarak işaretlenmelidir. Aksi halde program derleme esnasında hata verecektir.
  • Bir sınıfı unsafe olarak belirtirsek o sınıf içinde gösterici kullanabiliriz.
  • unsafe class Sinif { ... }
  • Herhangi bir metodun içinde bir unsafe bloğu oluşturarak o bloğun içinde gösterici kullanabiliriz.
  • int Metot() { unsafe { ... } }
  • Normal bir metodu unsafe olarak belirterek o metot içinde gösterici kullanabiliriz.
  • unsafe int Metot() { ... }
  • Özellikleri unsafe olarak belirterek yeni bir gösterici oluşturabiliriz. Bu durumda sınıfı unsafe olarak belirtmeye gerek kalmaz. Ancak bir metot içinde bir gösterici oluşturabilmek için ya o metodun unsafe olarak bildirilmesi ya da bir unsafe bloğunun açılması gerekir. Ayrıca içinde gösterici kullandığımız bir kaynak kod dosyası normal yollarla derlenemez. İçinde gösterici kullandığımız bir kaynak kod dosyamızı aşağıdaki iki yoldan biriyle derleriz.
  • csc /unsafe KaynakKod.cs
  • veya
  • csc -unsafe KaynakKod.cs
  • Çok istisnai durumlar dışında C # ‘ta pointerlara ihtiyaç duyulmaktadır.
  • Bu durumları aşağıdaki gibi sıralayabiliriz.
  • Geriye uyumluluk(Backward compatibility): COM ve WinAPI ‘deki fonksiyonlar gibi pointerları sık kullanan fonksiyonları C# ile çağırabilmek için parametre olarak gösterici alan fonksiyonlara gösterici gönderdiğimiz durumlarda kullanabiliriz.
  • Performans: Belleğe direk eriştiği için performansı aşırı derecede yükselttiği için kullanılır.
  • Alt seviye İşlemler: donanım arayüzleri ile direk ilişkili olduğu için kullanımları mecburi gibidir.
  • Hata Ayıklayıcı Programlar: hata ayıklayıcı programları yazabilmek için belleğe direk erişim sağlanmalıdır. Bu durumda pointer kullanımı şarttır.

Gösterici Bildirimi

  • Gösterici bildirimi ilgili yapı adının sonuna * işareti koyularak yapılır. Örnekler:
  • char* gosterici1;
  • int* gosterici2;
  • Bu göstericilerden birincisi bir char türünden nesnenin (değişkenin), ikincisi de bir int türünden nesnenin adresini tutabilir.
  • Birden fazla aynı türde gösterici oluşturmak için normal veri türlerinde olduğu gibi virgül kullanılabilir.
  • Örnek:
  • int* gosterici1, gosterici2;
  • Göstericileri sabit ifadeler ile de bildirebiliriz. Örnek:
  • double* gosterici=(double*)123456;
  • Burada bellekteki 123456 adresi gosterici göstericisine atanıyor. Ancak biz 123456 adresinde ne olduğunu bilmediğimiz için bu tür bir kullanım son derece tehlikelidir.
  • & operatörü:
  • Bu operatör adres operatörüdür. & işlemi önünde yer aldığı değişkenin adresini döndürür. Örneğin aşağıda int türünden bir pointer’ a daha önceden tanımlanan int türünden bir nesnenin adresi atanmaktadır.
  • int sayi=99; int* p; p=&sayi;
  • * Operatörü:
  • * operatörü bir adresteki bilgileri elde etmek ve değiştirmek için kullanılır. Aşağıda int üründe bir adres olan sayi nesnesinin adresine * operatörü ile yeni değer atanıyor.
  • int sayi=99; int* p; p=&sayi; *p=100;
  • Notlar:
  • 1-) Henüz adresi olmayan bir göstericiye değer atanamaz. Örneğin şu kod hatalıdır:
  • int* gosterici; *gosterici=10;
  • 2-) Ancak henüz bir değeri olmayan bir nesnenin adresi alınabilir. Yani şu kod hata vermez:
  • int a; int* ptr=&a;

Göstericiler Arasında Tür Dönüşümü

  • Göstericiler arasında bilinçli tür dönüşümü yapılabilir. Ancak dikkatli olunmalıdır. Çünkü büyük türün küçük türe dönüşümünde veri kaybı yaşanabilir.
  • Küçük türün büyük türe dönüşümünde de küçük tür bellekte kendine ait olmayan alanlardan da alır. Dolayısıyla her iki durumda da istemediğimiz durumlar oluşabilir. Göstericiler arasında bilinçsiz tür dönüşümü ise imkansızdır. Örnek bir program:
  • using System;
  • class Gostericiler {
  • unsafe static void Main()
  • { char c='A'; int i=80; char* cg=&c;
  • int* ig=&i; cg=(char*)ig; Console.WriteLine(*cg); }
  • }
  • Bu program sonucunda ekrana P yazılacaktır. (80'in Unicode karşılığı P'dir.) Bu programda herhangi bir veri kaybı gerçekleşmedi. Çünkü 80 char türünün kapasitesindeydi.
  • Göstericiler yapı nesnelerinin bellekteki adreslerini tutarlar. İşte bu adresi elde etmek için ilgili gösterici bir tam sayı türüne dönüştürülmelidir. Örnek:
  • using System;
  • class Gostericiler
  • { unsafe static void Main()
  • { int i=80; int* ig=&i; uint adres=(uint)ig; Console.WriteLine("{0:X}",adres); }
  • }
  • Bu program sonucunda benim bilgisayarım 13F478 çıktısını verdi. Ancak bu sizde değişebilir. Çünkü işlemcinin verileri nereye koyacağını hiç birimiz bilemeyiz. Ayrıca adresi ekrana yazdırırken formatlama yapıp 16'lık düzende yazdırdığımın da farkında olmalısınız. Çünkü bellek adresleri genellikle 16'lık düzendeki sayılarla ifade edilir.
  • Göstericilerin adreslerini elde ederken uint türüne dönüşüm yapmak zorunlu değildir. İstediğiniz tam sayı türüne dönüşüm yapabilirsiniz. Ancak uint, bir bellek adresini tam olarak tutabilecek en küçük veri tipi olduğu için ilgili göstericiyi uint türüne dönüştürmeniz tavsiye edilir

Önişlemci Komutları- #define

  • #define komutu bir sembol tanımlamak için kullanılır. Sembollerin tek başlarına bir anlamı yoktur.
  • #define ile sembol tanımlama program kodlarının en başında, (using deyimlerinden de önce) olmalıdır.
  • Örnek program:
  • #define ENGLISH
  • #define TURKISH
  • using System;
  • class Onislemci { static void Main() { } }
  • Bu programda ENGLISH ve TURKISH isimli iki sembol tanımlanmıştır. Diğer bütün önişlemci komutlarında olduğu gibi önişlemci komut parçaları arasında (örneğin #define ileTURKISH arasında) en az bir boşluk olmalıdır. Aynı sembolün tekrar tekrar tanımlanması hata verdirmez.
  • #if , #endif komutları bir sembolün tanımlanmış olup olmamasına göre birtakım kodların derlenip derlenmemesinin sağlanması için kullanılır. Örnek program:
  • #define ENGLISH
  • using System;
  • class Onislemci { static void Main()
  • { Console.WriteLine("Programa hoş geldiniz.");
  • #if ENGLISH Console.WriteLine("Bu program ENGLISH"); #endif }
  • }
  • Bu program ekrana şu çıktıyı verecektir.
  • Programa hoş geldiniz. Bu program ENGLISH
  • Eğer programın başına #define ENGLISH satırını eklemeseydik program çıktısındaki ikinci satır olmayacaktı.

 

Önişlemci Komutları-#undef

  • #undef, #define ile tanımlanmış bir sembolü kaldırmak için kullanılır.
  • Olmayan bir sembolü kaldırmaya çalışmak hata verdirmez. Programın herhangi bir satırında olabilir. Örnek program:
  • #define ENGLISH
  • using System;
  • #undef ENGLISH
  • class Onislemci
  • {
  • static void Main() , … }
  •  }
  • Sembollerin büyük ya da küçük harf olması zorunlu değildir. Ancak tamamen büyük harf okunurluğu artırdığı için tavsiye edilir. Sembollerin büyük-küçük harf duyarlılığı vardır

Önişlemci Komutları- #if , #endif

  • #if , #endif komutları bir sembolün tanımlanmış olup olmamasına göre birtakım kodların derlenip derlenmemesinin sağlanması için kullanılır. Örnek program:
  • #define ENGLISH
  • using System;
  • class Onislemci { static void Main()
  • { Console.WriteLine("Programa hoş geldiniz.");
  • #if ENGLISH Console.WriteLine("Bu program ENGLISH"); #endif }
  • }
  • Bu program ekrana şu çıktıyı verecektir.
  • Programa hoş geldiniz. Bu program ENGLISH
  • Eğer programın başına #define ENGLISH satırını eklemeseydik program çıktısındaki ikinci satır olmayacaktı.

Önişlemci Komutları- #else

  • #else önişlemci komutu C#'taki else ile aynı göreve sahiptir. Koşul sağlanmışsa bir kod bloğunun derlenmesini sağlayan #if komutu ile birlikte kullanılır. Örnek:
  • #define ENGLISH
  • using System;
  • class Onislemci{ static void Main()
  • { Console.WriteLine("Programa hoş geldiniz.");
  • #if ENGLISH Console.WriteLine("Bu program ENGLISH");
  • #else Console.WriteLine("Bu program ENGLISH değil");
  • #endif
  • }
  • }

Önişlemci Komutları- #elif

  • #elif, C#'taki elseif 'in kısaltılmışıdır. Yani değilse bir de bu koşula bak anlamı verir. Örnek program:
  • #define ENGLISH
  • using System;
  • class Onislemci {
  • static void Main() {
  • Console.WriteLine("Programa hoş geldiniz.");
  • #if ENGLISH Console.WriteLine("Bu program ENGLISH");
  • #elif TURKISH Console.WriteLine("Bu program TURKISH");
  • #else Console.WriteLine("Bu program hem TURKISH, hem de ENGLISH değil"); #endif } }
  • #elif komutlarının sayısını bir #if-#endif aralığında istediğimiz kadar artırabilir.

Henüz Yorum Yapılmamış, İlk Yorumu Siz Yapın

Yorum Yollayın