C Programlama

Ek Bilgiler

Programlamaya Giriş

Programlama Nedir?

C programlama diline başlamadan önce, isterseniz programlama ve programlama dilleri konusuna biraz değinelim:

Bilgisayar kullanılmaya başladığından bu yana, sıklıkla yapılan hatalardan biri de (daha çok bilim kurgu film ve dizilerinin etkisiyle) bilgisayarın verilen sesli komutları yerine getiren akıllı bir cihaz olarak görülmesidir. Sanıldığının aksine, bilgisayar sadece ikili (binary) sayı sisteminde verilen komutları (makine dili) yerine getirerek işlem yapabilen bir cihazdır. Başlangıçta, bu ifade kafalarda karışıklığa yol açsa da, konunun detaylarına girildikçe bu sorun çözülecektir. Kısaca açıklamaya çalışırsak:

Ana dilinden başka bir dil bilmeyen biri ile anlaşmak için sadece onun dilini kullanmak zorunda olduğumuz gibi bilgisayarla anlaşmak ve ona istediğimiz işlemleri yaptırabilmek içinde bilgisayarın anladığı tek dil olan makine dilini kullanmak zorundayız. Bilgisayarın merkezi işlem birimi (Central Processing Unit) sadece makine dili kodlarına işlem yapar. Çünkü sadece makine dilini anlar.

Her farklı tipteki CPU'nun kendine has bir makine dili vardır.

CPU, makine kodlarının yer aldığı bellek birimlerine bakar, buradaki ikili sistem değerlerini alır, değerlendirir ve kendisi için ne anlam ifade ediyorsa ona göre işlem yapar.

Makine dilini CPU tarafından işlem yapılan bir seri talimat olarak tanımlayabiliriz.

Sonuç olarak, bilgisayara bir işlem yaptırmak istiyorsak, talimatlarımızı makine dilinde (ikili sayı sisteminde) bilgisayarın belleğine yükleyip çalıştırmamız gerekir.

Programları Belleğe Yüklemek

Şimdi, bu işlemi ne şekilde gerçekleştirebileceğimizi incelemeye çalışalım:

Bilgisayarın belleğine istediğimiz talimatların yüklenip çalıştırılmasını temel olarak üç farklı şekilde gerçekleştirebiliriz:

  1. Direk olarak belleğe makine dili kodları yükleyerek,
  2. Assembler programlama dili kullanarak,
  3. Yüksek seviyeli programlama dili kullanarak.

Yukarıdaki seçenekleri sırasıyla incelemeye çalışalım:

Direk Olarak Belleğe Makine Dili Kodları Yüklemek

Şu andan itibaren bilgisayarın çalışma prensiplerini anlamak amacıyla oluşturacağımız örnekler için, Windows işletim sistemleriyle birlikte kullanıcıların hizmetine sunulan, DEBUG programını kullanmaya başlayacağız.

Debug programının öncelikli amacı çalıştırılabilir MS-DOS (Microsoft Disk Operating System) dosyalarını çalıştırmak ve bu dosyalarda bulunan hataları bulmak ve düzeltmektir. Bununla birlikte, debug programını kullanarak, belleğe makine dili kodları yükleyebilir, bunları çalıştırabilir, kısa assembly dili programları yazabilir ve makine diline çevirebilir, makine dilindeki kodları assembly diline çevirebilir, bellekte yer alan değerleri görüntüleyebilir ve buna benzer diğer işlemleri de gerçekleştirebiliriz. Debug programı hakkındaki ayrıntılı bilgilere Windows işletim sistemi 'Yardım ve Destek' bölümünden ulaşabilirsiniz.

Dilerseniz şimdi hep birlikte uygulamaya başlayalım. Debug programını çalıştırmak için, önce Başlat-Çalıştır kutusunda 'cmd' yazarak, bir komut penceresi açalım. Karşımıza aşağıdaki gibi bir ekran gelecektir:

C:\> _

Karşımıza gelen ekranda yanıp sönen imleç bize bir komut girebileceğimizi göstermektedir. Bu komut satırında 'debug' yazıp 'Enter' tuşuna basın. Artık ekran aşağıdaki gibi bir görüntü alacaktır:

C:\>debug 
-

Karşımıza çıkan tek çizgi artık debug programının çalıştığını ve verilecek komutları yerine getirmeye hazır olduğunu göstermektedir. Eğer burada '?' karakteri girer ve 'Enter' tuşuna basarsanız debug programının alt komutlarını görebilirsiniz.

C:\>debug 
- d100

Debug programının d alt komutu bilgisayarın tanımlanmış bellek içeriğini göstermek için kullanılmaktadır. Yukarıdaki komutu yazdığımızda karşımıza aşağıdakine benzer bir ekran çıkacaktır. Sizin bilgisayarınızda görünen değerler tamamen farklı olabilir:

C:\>debug 
- d100
0CD4:0100  6E 64 69 73 69 20 81 7A-65 72 69 6E 65 20 6B 6F   ndisi .zerine ko
0CD4:0110  70 79 61 6C 61 6E 61 6D-61 7A 0D 0A 34 00 C3 0C   pyalanamaz..4... 
0CD4:0120  65 72 73 69 7A 20 64 69-73 6B 20 61 6C 61 6E 8D   ersiz disk alan.
0CD4:0130  0D 0A 16 47 65 87 65 72-73 69 7A 20 6B 6F 64 20   ...Ge.ersiz kod 
0CD4:0140  73 61 79 66 61 73 8D 0D-0A 10 47 65 87 65 72 73   sayfas....Ge.ers
0CD4:0150  69 7A 20 74 61 72 69 68-0D 0A 10 47 65 87 65 72   iz tarih...Ge.er 
0CD4:0160  73 69 7A 20 7A 61 6D 61-6E 0D 0A 0E 47 65 87 65   siz zaman...Ge.e 
0CD4:0170  72 73 69 7A 20 79 6F 6C-0D 0A 30 44 65 76 61 6D   rsiz yol..0Devam

Tablo 1.1

Yukarıdaki ekran görüntüsünde en solda yer alan değerler bellek adreslerini, ortada yer alan değerler bellek adreslerinde yer alan değerleri onaltılık (Hexadecimal) sayı sisteminde, en sağdaki değerler ise bellek adreslerinde yer alan değerleri ASCII olarak gösterir. Ancak sadece standart ASCII karakterler gösterilebilir. Özel karakterlerin yerine ise sadece '.' karakteri gösterilir.

Şu anda bilgisayar belleğinin 128 byte'lık bölümü ekranda gösterilmektedir. Toplam 8 satır ve her satırda 16 byte değer yer almaktadır. Debug programı normal olarak onaltılık sayı sistemi ile işlem yaptığından bellek adresleri (0CD4:0100) ve bu adreslerde yer alan değerler (6E gibi) bu sayı sisteminde gösterilmektedir.

Sadece ilk satırı incelemeye çalışırsak:

 0CD4:0100  6E 64 69 73 69 20 81 7A-65 72 69 6E 65 20 6B 6F   ndisi .zerine ko 

16 byte'lık bellek bloğu için bellek adresleri ve bu adreslerde yer alan değerler şu şekilde gösterilebilir:

                               Bellekte Yer Alan Değer
                _______________________________________________________
 
Bellek Adresi    16'lık Sayı Sistemi    ASCII Kod    İkili Sayı Sistemi

0CD4:0100                6E                 n             0110 1110
0CD4:0101                64                 d             0110 0100
0CD4:0102                69                 i             0110 1001
0CD4:0103                73                 s             0111 0011
0CD4:0104                69                 i             0110 1001
0CD4:0105                20                               0010 0000
0CD4:0106                81                 .             1000 0001
0CD4:0107                7A                 z             0111 1010
0CD4:0108                65                 e             0110 0101
0CD4:0109                72                 r             0111 0010
0CD4:010A                69                 i             0110 1001
0CD4:010B                6E                 n             0110 1110
0CD4:010C                65                 e             0110 0101
0CD4:010D                20                               0010 0000
0CD4:010E                6B                 k             0110 1011
0CD4:010F                6F                 o             0110 1111

Tablo 1.2

Tablo 1.2'de, bellek adreslerinde yer alan değerleri 3 farklı sistemde gösterdik. Gerçek ortamda bilgisayar bu adreslerde değerleri ikili sayı sisteminde tutar. Ancak, debug programı bu değerleri gösterimi daha pratik ve kullanışlı olduğu için onaltılık sayı sistemini kullanır.

Debug programının bellek içeriğini gösterme ve temel kullanım prensiplerine kısaca göz attıktan sonra, artık belleğe değer yükleme işlemlerine başlayabiliriz. Bu işlem için debug e (Enter) alt komutunu kullanabiliriz. Debug ortamında yukarıdaki komutu girerseniz karşınıza aşağıdakine benzer bir görüntü gelir:

C:\>debug
-e100
0CD4:0100 6E._ 

Dikkat ettiğimizde, d100 komutu ile gösterdiğimiz bellek bloğunun ilk başında yer alan 6E (Sizin bilgisayarınızda farklı bir değer olabilir)değerini ve hemen sağında yanıp sönen bir imleç görürüz. Belleğe veri giriş konumunda iken Enter tuşuna basarsak belleğe veri giriş konumundan çıkarız. Eğer bu konumda bir değer girmeden BOŞLUK tuşuna basarsak bellekte bulunan değer değişmeden bir sonraki bellek konumuna geçiş yaparız.

Eğer bu konumda 2 haneli bir onaltılık değer girer ve BOŞLUK (SPACE) tuşuna basarsak, girdiğimiz değer 6E değeri yerine belleğe yerleşir ve bir sonraki bellek konumuna geçiş yaparız. Bu kez, bilgisayar yeni bellek konumunda bulunan değeri ekrana yazar ve yeni bir değer girmemizi bekler. Bu şekilde aşağıdaki değerleri sırasıyla belleğe yüklemeye çalışalım:

C:\>debug
-e100
0CD4:0100 6E.B2 64.41 69.B4 73.2 69.CD 20.21 81.CD 7A.20 

Son olarak Enter tuşuna basarsak belleğe değer girme konumundan çıkmış ve 0CD4:0100 adresinden başlayarak bellekte yer alan eski değerlerin yerine aşağıdaki 8 adet onaltılık değeri sırasıyla yazmış oluruz:

B2 41 B4 2 CD 21 CD 20

Bu durumda, debug komut satırında, d100 alt komutunu kullanırsak Tablo 1.1'de gösterilen bellek içeriği aşağıdaki hale gelir:

C:\>debug
-d100
0CD4:0100  B2 41 B4 02 CD 21 CD 20-65 72 69 6E 65 20 6B 6F   .A...!. erine ko
0CD4:0110  70 79 61 6C 61 6E 61 6D-61 7A 0D 0A 34 00 C3 0C   pyalanamaz..4... 
0CD4:0120  65 72 73 69 7A 20 64 69-73 6B 20 61 6C 61 6E 8D   ersiz disk alan.
0CD4:0130  0D 0A 16 47 65 87 65 72-73 69 7A 20 6B 6F 64 20   ...Ge.ersiz kod 
0CD4:0140  73 61 79 66 61 73 8D 0D-0A 10 47 65 87 65 72 73   sayfas....Ge.ers
0CD4:0150  69 7A 20 74 61 72 69 68-0D 0A 10 47 65 87 65 72   iz tarih...Ge.er 
0CD4:0160  73 69 7A 20 7A 61 6D 61-6E 0D 0A 0E 47 65 87 65   siz zaman...Ge.e 
0CD4:0170  72 73 69 7A 20 79 6F 6C-0D 0A 30 44 65 76 61 6D   rsiz yol..0Devam

Tablo 1.3

Artık bellekte çalışmaya hazır ve 8 byte'tan oluşan bir programımız (turuncu renkle gösterilen) var. Dilerseniz bu makine dili kodlarını birde ikili sayı sisteminde görelim:

                                  Bellekte Yer Alan Değer
                ________________________________________________________
 
 Bellek Adresi  16'lık Sayı Sistemi     ASCII Kod     İkili Sayı Sistemi

 0CD4:0100              B2                   .               1011 0010
 0CD4:0101              41                   A               0100 0001
 0CD4:0102              B4                   .               1011 0100
 0CD4:0103              02                   .               0000 0010
 0CD4:0104              CD                   .               1100 1101
 0CD4:0105              21                   !               0010 0001
 0CD4:0106              CD                   .               1100 1101
 0CD4:0107              20                                   0010 0000

Tablo 1.4

Bilgisayarımızın merkezi işlem birimi artık kendisi için bir anlam ifade eden ve bellekte yer alan bu ikili sayı sistem değerlerine işlem yapabilir.

Debug programının g alt komutunu kullanarak bellekte bulunan bir programı çalıştırabiliriz:

-g

Debug ortamında iken yukarıdaki komutu yazar ve Enter tuşuna basarsanız, aşağıdaki gibi bir ekran karşınıza gelir:

C:\>debug
-g
A
Program normal olarak sonlandırıldı
-

Böylece, belleğe direk olarak yüklediğimiz makine dili kodlarından oluşan programı çalıştırarak ekrana 'A' karakterini yazdırmış olduk.

Assembler Programlama Dili İle Belleğe Makine Dili Kodları Yüklemek

Biraz önce gerçekleştirdiğimiz direk olarak belleğe makine kodlarını yüklemek ve çalıştırmak oldukça zahmetli ve uzun bir iş idi. Ayrıca her farklı tipteki CPU'nun kendine has bir makine dili olduğunu da hesaba katarsak bu işlemlerin daha da karmaşık hale geleceği görülmektedir.

Şimdi, debug a (Assemble) alt komutunu kullanarak Assembly dilinde talimatlar yazarak, biraz önce yazdığımız programın aynısını yazmaya çalışalım. Önce debug ortamına tekrar girip aşağıdaki komutu yazalım:

-a100

Yukarıdaki komutu yazar ve Enter tuşuna basarsanız, karşınıza aşağıdaki gibi ekran görüntüsü gelir:

C:\>debug
-a100
0CD4:0100 -

Bu durumda iken, aşağıdaki 4 satırı sırasıyla girin ve her satırdan sonra Enter tuşuna basın:

mov dl, 41
mov ah, 2
int 21
int 20

Bu girdiğiniz değerler Assembly dili kodlarıdır. Ekranınız aşağıdakine benzer bir görüntü alacaktır:

C:\>debug
-a100
0CD4:0100 mov dl, 41
0CD4:0102 mov ah, 41
0CD4:0104 int 21
0CD4:0106 int 20
0CD4:0108
-

Bu konumda iken, debug komut satırında, d100 alt komutunu kullanırsak bellek içeriği aşağıdaki hale gelir:

0CD4:0100  B2 41 B4 02 CD 21 CD 20-65 72 69 6E 65 20 6B 6F   .A...!. erine ko
0CD4:0110  70 79 61 6C 61 6E 61 6D-61 7A 0D 0A 34 00 C3 0C   pyalanamaz..4... 
0CD4:0120  65 72 73 69 7A 20 64 69-73 6B 20 61 6C 61 6E 8D   ersiz disk alan.
0CD4:0130  0D 0A 16 47 65 87 65 72-73 69 7A 20 6B 6F 64 20   ...Ge.ersiz kod 
0CD4:0140  73 61 79 66 61 73 8D 0D-0A 10 47 65 87 65 72 73   sayfas....Ge.ers
0CD4:0150  69 7A 20 74 61 72 69 68-0D 0A 10 47 65 87 65 72   iz tarih...Ge.er 
0CD4:0160  73 69 7A 20 7A 61 6D 61-6E 0D 0A 0E 47 65 87 65   siz zaman...Ge.e 
0CD4:0170  72 73 69 7A 20 79 6F 6C-0D 0A 30 44 65 76 61 6D   rsiz yol..0Devam

Tablo 1.5

Biraz önce debug e komutunu kullanarak belleğe bir bir yerleştirdiğimiz makine kodlarının aynısının (turuncu renkle gösterilen) belleğe yerleşmiş olduğunu görürüz. Biz bu işlemi direk olarak gerçekleştirmediğimiz halde, makine kodları belleğe nasıl yerleşti? Bu işlemi gerçekleştiren debug programının a alt komutudur. Bu komut Assembly dilinde yazdığımız kodları makine diline çeviren bir çeşit Assembler programıdır.

Artık bu programı da biraz önceki program gibi Debug programının g alt komutunu kullanarak çalıştırabiliriz:

-g
A
Program normal olarak sonlandırıldı
-

Böylece, Assembly dilinde yazdığımız kodları debug a komutu ile makine diline diline çevirerek belleğe yerleştirmiş olduğumuz programı çalıştırarak ekrana 'A' karakterini yazdırmış olduk.

Hatırlarsak, ana dilinden başka bir dil bilmeyen biri ile anlaşmak için sadece onun dilini kullanmak zorunda olduğumuz gibi bilgisayarla anlaşmak ve ona istediğimiz işlemleri yaptırabilmek içinde bilgisayarın anladığı tek dil olan makine dilini kullanmak zorunda olduğumuzu belirtmiştik.

Dikkat edersek, belleğe direk makine kodları yüklediğimizde bilgisayar ile aramızda herhangi bir aracı kullanmadık. Bilgisayarın bildiği makine dilini kullanarak onunla anlaştık. Ancak, Assembly dilinde kodlar yazıp debug a komutu ile bu kodları makine diline çevirip belleğe yüklediğimizde bilgisayarla aramıza debug assembler özelliğini aracı olarak koymuş olduk. Bu aracı bizimle bilgisayar arasında bir tür tercüman görevi yapmış oldu. Konunun daha iyi anlaşılması için debug u alt komutunu kullanarak, daha önce debug a komutu ile makine diline çevirip belleğe yüklediğimiz Assembly dili kodlarını, tekrar eski haline çevirmeye çalışalım. Kodlar bellekte yüklü iken u100, 106 komutunu girerseniz aşağıdakine benzer bir görüntü karşınıza gelir:

-u100, 106
0CD4:0100 B241          MOV DL,41
0CD4:0102 B402          MOV AH,02
0CD4:0104 CD21          INT 21
0CD4:0106 CD20          INT 20
-

Ortada yer alan mavi renkli değerler makine dili kodlarını, sağ tarafta yer alan turuncu renkli değerler ise Assembly dili kodlarını yani yazdığımız ilk Assembly dili programını gösterir. Assembly dili kodlarını makine diline çevirmek için debug a alt komutunu, makine dili kodlarını Assembly dili kodlarına çevirmek içinse debug u alt komutunu kullanmış olduk.

Buraya kadar bahsi geçen konuları hiç incelemeden direk olarak yüksek seviyeli dillerle programlama konusuna girebilirdik. Ancak, konunun daha iyi anlaşılması ve programlama ortamlarının zamanla ihtiyaçlara paralel olarak ne şekilde geliştiği konusunda da fikir edinebilmemiz için bu temel bilgilerin verilmesinin doğru bir tercih olduğuna inandık.

Sağlam temel ve bilgi üzerine oturtulmamış programcılık deneyimlerinin ileride sorun yaratacağı ve bazı noktalarda eksik bilginin geri dönüş ihtiyacı doğuracağı düşüncesinde sanırım birleşebiliriz.

Yüksek Seviyeli Programlama Diliyle Makine Dili Kodları Yüklemek

Program bilgisayar tarafından yerine getirilmek üzere hazırlanmış tek bir talimat veya talimatlar serisidir. Programlama bu talimatların hazırlanması işlemidir.

Bilgisayar kendisine verilen talimatları sırasıyla yerine getiren bir makinedir. Zaten verilen bu talimatlar zincirine program adı verilir.

Bilgisayar programlama ihtiyaçları arttıkça, bu programları daha seri bir şekilde üretebilecek bir sistemin varlığına gereksinim duyulmuştur. Bu safhaya gelene kadar incelediğimiz her iki yöntemde sistemin ihtiyaçlarını karşılamada yetersiz kalınca yüksek seviyeli programlama dilleri olarak adlandırılan programlama dilleri devreye girmiştir.

Yüksek seviyeli programlama dillerinin en büyük özelliği programcı ile donanım arasındaki ilişkiyi olanak dahilinde en düşük seviyeye indirmek ve donanım seviyesinde yapılan işlemlerin programlama dilleri yoluyla yapılmasını sağlamaktır. Ayrıca, programcıya daha anlaşılır ifadeler taşıyan kelimeler kullanma olanağı sunar.

Yüksek seviyeli dilleri kullanmanın en önemli avantajlarından biri de farklı tipteki CPU'lar için farklı programlar yapmaya gerek olmamasıdır.

Yüksek seviyeli dillerde programlama yapabilmek için aşağıda gösterilen programlara ihtiyacımız olacaktır:

Kullanıcı başlangıçta tamamen metinlerden oluşan ve kaynak dosya adı verilen bir dosya oluşturur. Kaynak dosya içinde yer alan komutlar anlaşılır ve İngilizce dili içinde yer alan anlamlı kelimelerden oluşur. Bu kaynak dosya derleyici tarafından makine kodlarına çevrilir. Ancak dosya bu haliyle bilgisayar tarafından çalıştırılamaz. Çalıştırılabilir hale getirilip .exe uzantılı bir dosya elde etmek için bağlayıcı tarafından işlem yapılır.

Günümüzde, Entegre Geliştirme Ortamı (IDE Integrated Development Environment) olarak adlandırılan programlama ortamları kullanılmaktadır. Bu ortamda bir programın oluşturulması için gereken yukarıda bahsi geçen 3 programa ilaveten bir de hata ayıklayıcı (Debugger) programı bulunur. Kullanılmakta olan programlama IDE'lerini ücretli (Shareware) ve ücretsiz (Freeware) olarak 2 sınıfa ayırabiliriz. Ücretli IDE'lerin bazıları sınırlı özelliklerle amatör kullanıcıların hizmetine ücretsiz olarak sunulmaktadır.

Programlama IDE'lerinin en faydalı yönü, ortam değiştirmeden bir programı yazabilmemize, derlememize, bağlamamıza, hata ayıklama işlemi yapmamıza ve çalıştırmamıza olanak sağlamasıdır.