İngilizce Kaynaklar


Diğer




D'nin C ile Karşılaştırılması

Not: Bu bir D1 karşılaştırmasıdır. Modern D'nin başka farklılıkları da var.

Bu bölüm, C programcılarına yönelik olarak D dilinin C'den olan bazı farklılıklarını gösteriyor. Nesne yönelimli programlama konusundaki farklarını ise C++ karşılaştırmasında okuyabilirsiniz.

Bu sayfadaki bilgiler Digital Mars'ın sitesindeki aslından alınmıştır.



Tür büyüklükleri
C
sizeof(int)
sizeof(char *)
sizeof(double)
sizeof(struct Foo)
D
int.sizeof
(char *).sizeof
double.sizeof
Foo.sizeof


Türlerin en küçük ve en büyük değerleri
C
#include <limits.h>
#include <math.h>

CHAR_MAX
CHAR_MIN
ULONG_MAX
DBL_MIN
D
char.max
char.min
ulong.max
double.min


Temel türler
C'den D'ye
                  bool  =>   bit 
                  char  =>   char 
           signed char  =>   byte 
         unsigned char  =>  ubyte 
                 short  =>   short 
        unsigned short  =>  ushort 
               wchar_t  =>  wchar 
                   int  =>   int 
              unsigned  =>  uint 
                  long  =>   int 
         unsigned long  =>  uint 
             long long  =>   long 
    unsigned long long  =>  ulong 
                 float  =>   float 
                double  =>   double 
           long double  =>   real 
_Imaginary long double  =>  ireal
  _Complex long double  =>  creal

char işaretsiz [unsigned] 8 bittir, wchar ise işaretsiz 16 bittir. İşaretli ve işaretsiz türler C'de değişik boyutta olabilirler, D'de aynıdırlar.



Özel kesirli sayı değerleri
C
#include <fp.h> 

NAN 
INFINITY 

#include <float.h> 

DBL_DIG 
DBL_EPSILON 
DBL_MANT_DIG 
DBL_MAX_10_EXP 
DBL_MAX_EXP 
DBL_MIN_10_EXP 
DBL_MIN_EXP 
D
double.nan 
double.infinity 
double.dig 
double.epsilon 
double.mant_dig 
double.max_10_exp 
double.max_exp 
double.min_10_exp 
double.min_exp 


Kesirli sayı bölümünden kalan
C
#include <math.h> 

float f = fmodf(x,y); 
double d = fmod(x,y); 
long double r = fmodl(x,y); 
D
float f = x % y; 
double d = x % y; 
real r = x % y; 


Kesirli sayı karşılaştırmalarında NAN

Not A Number'ın kısaltması olan NAN, bir kesirli sayının bit gösterimi düzeyinde geçersiz olduğu anlamına gelir. C, NAN geçersiz değerinin sayı karşılaştırmalarında yer almasının nasıl bir sonuç vereceğini belirlemez.

C
#include <math.h> 

if (isnan(x) || isnan(y)) 
   sonuc = FALSE; 
else 
   sonuc = (x < y); 
D
sonuç = (x < y);        // x veya y 'nan' olduğunda 'false'tur


Güvenli kodlamanın vazgeçilmez parçası assert

C'de assert dilin parçası değildir ama __FILE__ ve __LINE__ makroları aracılığıyla kullanışlı bilgi verir. D'de ise assert dilin parçasıdır.

C
#include <assert.h> 

assert(e == 0); 
D
assert(e == 0); 


Dizi elemanlarını ilklemek
C
#define DIZI_UZUNLUGU        17 
int dizi[DIZI_UZUNLUGU]; 
for (i = 0; i < DIZI_UZUNLUGU; i++) 
   dizi[i] = deger; 
D
int dizi[17]; 
dizi[] = değer;


Dizi elemanlarını sırayla ziyaret etmek

C'de diziler kendi uzunluklarını bilmedikleri için uzunluk ya ayrı olarak tanımlanır, ya da sizeof işlecinden yararlanılır. D'de ise dizilerin uzunlukları dizinin bir niteliğidir [property].

C
#define DIZI_UZUNLUGU        17 
int dizi[DIZI_UZUNLUGU]; 
for (i = 0; i < DIZI_UZUNLUGU; i++) 
   fonksiyon(dizi[i]); 

veya

int dizi[17]; 
for (i = 0; i < sizeof(dizi) / sizeof(dizi[0]); i++) 
   fonksiyon(dizi[i]);
D
int dizi[17]; 
for (i = 0; i < dizi.length; i++) 
   fonksiyon(dizi[i]); 

veya daha da iyisi:

int dizi[17]; 
foreach (int değer; dizi)
   fonksiyon(değer); 


Değişken uzunlukta diziler

C'de uzunluğu tutmak için ayrı bir değişken gerekir, ve dizinin uzunluğu değiştiğinde onun da değeri değiştirilir. D ise dinamik dizileri desteklediği için gereken bellek yönetimi de otomatik olarak halledilir.

C
#include <stdlib.h> 

int dizi_uzunlugu; 
int *dizi; 
int *yeni_dizi; 

yeni_dizi =
       (int *)realloc(dizi, (dizi_uzunlugu + 1) * sizeof(int));
if (!yeni_dizi) 
   error("bellek yetersiz"); 
dizi = yeni_dizi; 
dizi[dizi_uzunlugu++] = x; 
D
int[] dizi; 

dizi.length = dizi.length + 1;
dizi[dizi.length - 1] = x; 


Dizgileri birleştirmek

C'de bu konuda çok sorun vardır: belleğin ne zaman geri verileceği, NULL işaretçiler, dizgilerin uzunluklarını bulmak, ve genel olarak bellek yönetimi. D'de ise char ve wchar türleri için yüklenmiş olan ~ işleci birleştirmek, ~= işleci ise sonuna eklemek anlamına gelir.

C
#include <string.h> 

char *s1; 
char *s2; 
char *s; 

// s1 ve s2'yi ekle ve sonucu s'ye yerleştir
free(s); 
s = (char *)malloc((s1 ? strlen(s1) : 0) + 
                   (s2 ? strlen(s2) : 0) + 1); 
if (!s) 
   error("bellek yetersiz"); 
if (s1) 
   strcpy(s, s1); 
else 
   *s = 0; 
if (s2) 
   strcpy(s + strlen(s), s2); 

// s'ye "merhaba" dizgisini ekle
char merhaba[] = "merhaba"; 
char *yeni_s; 
size_t s_uzunluk = s ? strlen(s) : 0; 
yeni_s = (char *)realloc(s,
                         (s_uzunluk + sizeof(merhaba) + 1)
                                               * sizeof(char));
if (!yeni_s) 
   error("bellek yetersiz"); 
s = yeni_s; 
memcpy(s + s_uzunluk, merhaba, sizeof(merhaba)); 
D
char[] s1; 
char[] s2; 
char[] s; 

s = s1 ~ s2; 
s ~= "merhaba"; 


Formatlı çıktı

D'de printf'e ek olarak tür güvenliği getiren writefln vardır.

C
#include <stdio.h> 

printf("Arabaları %d kere çağırıyoruz!\n", kac_kere);
D
printf("Arabaları %d kere çağırıyoruz!\n", kaç_kere);

veya daha güvenli olarak

import std.stdio;

writefln("Arabaları %s kere çağırıyoruz!", kaç_kere);


Fonksiyonları önceden bildirmek

C'de her fonksiyonun kullanılmadan önce bildirilmiş olması gerekir. D'de ise programa bir bütün olarak bakıldığı için, fonksiyon bildirimleri gereksiz olmalarının yanında yasal bile değillerdir. Hatalara elverişli bu külfetten kurtulmuş olarak fonksiyonları istediğimiz sırada yazabiliriz.

C
// bildirim
void ileride_tanimli_fonksiyon(); 

void fonksiyon() 
{   
   ileride_tanimli_fonksiyon(); 
} 

// tanim
void ileride_tanimli_fonksiyon() 
{   
   ... 
} 
D
void fonksiyon() 
{   
   ileride_tanımlı_fonksiyon(); 
} 

// tanım
void ileride_tanımlı_fonksiyon() 
{   
   ... 
} 


Parametre almayan fonksiyonlar

D'de bir fonksiyonun parametre almadığının açıkça belirtilmesine gerek yoktur; boş bırakılan parametre listesi zaten o anlama gelir.

C
void fonksiyon(void);
D
void fonksiyon()
{
   ...
}


Etiket kullanan break ve continue deyimleri

C'de break ve continue deyimleri en içteki döngüyü veya switch'i etkiler. En dıştaki döngüden de çıkmak istendiğinde goto kullanmak gerekir. D'de ise döngülere ve switch'lere de etiket verilebilir ve break ve continue deyimlerinde etiket belirtilerek istenen düzeydeki döngü veya switch belirtilebilir.

C
    for (i = 0; i < 10; i++) 
    {   
       for (j = 0; j < 10; j++) 
       {   
           if (j == 3) 
               goto Dis_Etiket; 
           if (j == 4) 
               goto Ic_Etiket; 
       } 
     Ic_Etiket: 
       ; 
    } 
Dis_Etiket: 
    ; 
D
Dış_Etiket: 
   for (i = 0; i < 10; i++) 
   {   
       for (j = 0; j < 10; j++) 
       {   
           if (j == 3) 
               break Dış_Etiket; 
           if (j == 4) 
               continue Dış_Etiket; 
       } 
   } 
   // 'break Dış_Etiket;' buraya getirir


goto deyimi

goto deyimi C'de de önerilmez ama bazen mecbur kalınır. Her ne kadar D'de gerekmese de, istendiğinde kullanılabilsin diye goto D'de de vardır.



typedef struct

Yapı tanımlarında typedef gerekmez.

C
typedef struct ABC { ... } ABC;
D
struct ABC { ... }


Dizgi aramak

Verilen bir dizgiyi bir dizgi listesinde aramak, oldukça yaygın bir işlemdir. Örneğin programın hangi komut satırı parametreleri ile çalıştırıldığını anlamak ve programın davranışını ona göre ayarlamak...

Bu işi C'de yapmak için birbirine denk üç veri yapısı kullanmak gerekir: enum, dizgi tablosu, ve switch içindeki case'ler. Bu üçünü denk tutmak listedeki dizgi sayısı arttığında oldukça güçleşebilir ve hatalara açık durumlar doğurur. Dahası, bu bir sıralı arama algoritması olduğu için, büyük listelerde yavaş da kalabilir. Öyle olduğunda zaman da bir hızlı eşleme tablosu kurmak gerekebilir ve iş iyice karmaşıklaşır.

D ise switch deyimlerinde dizgilere izin vererek bu işlemi büyük ölçüde kolaylaştırır. Listeye yeni değerler eklemek son derece basit hale gelir ve gerektiği durumlarda daha hızlı algoritmalar kullanmak da derleyiciye bırakılmış olur.

C
#include <string.h> 
void islem_yap(char *s) 
{   
   enum Degerler { Merhaba, GuleGule, Belki, deger_adet }; 
   static char *tablo[] = { "merhaba", "güle güle", "belki" }; 
   int i; 

   for (i = 0; i < deger_adet; i++) 
   {   
       if (strcmp(s, tablo[i]) == 0) 
           break; 
   } 
   switch (i) 
   {   
       case Merhaba:   ... 
       case GuleGule: ... 
       case Belki:   ... 
       default:      ... 
   } 
}
D
void işlem_yap(char[] s) 
{   
   switch (s) 
   {   
       case "merhaba":   ... 
       case "güle güle": ... 
       case "belki":   ... 
       default:        ... 
   } 
} 


Yapı üyelerinin bellek yerleşimleri [alignment]

C'de bunun bir yolu, istenen yerleşimi derleyici ayarlarıyla belirtmektir. Öyle yapınca, bütün yapılar etkilenmiş olurlar ve bütün kaynak dosyaların baştan derlenmeleri gerekir. Bu işi kolaylaştırmak için #pragma'lar kullanılır; ancak #pragma'lar maalesef derleyiciye bağlı ve taşınmaz olanaklardır. D'de bu konuda taşınabilir bir çözüm sunulmuştur.

C
#pragma pack(1) 
struct ABC 
{   
   ... 
}; 
#pragma pack() 
D
struct ABC 
{   
   int z;            // z varsayılan ayara göre yerleştirilecek

   align (1) int x;  // x byte sınırına yerleştirilecek
   align (4) 
   {   
     ...             // {} içinde tanımlanan üyeler dword
                     // sınırına yerleştirilecekler
   } 
   align (2):        // bu noktadan sonra word sınırına geçilir

   int y;            // y word sınırındadır
} 


İsimsiz struct'lar ve union'lar

Bazı durumlarda üyelerin yerleşimleri için yapılardan ve birliklerden [union] yararlanılır. C bunların isimsiz olarak tanımlanmalarına izin vermediği için kullanılmayacak isimler uydurmak gerekir. O isimlerden kurtulmak için de makrolardan yararlanılır. D ise bu yapıların isimsiz olarak tanımlanmalarına izin verir.

C
struct Foo 
{
   int i; 
   union Bar 
   {
      struct Abc { int x; long y; } _abc; 
      char *p; 
   } _bar; 
}; 

#define x _bar._abc.x 
#define y _bar._abc.y 
#define p _bar.p 

struct Foo f; 

f.i; 
f.x; 
f.y; 
f.p; 
D
struct Foo 
{
   int i; 
   union 
   {
      struct { int x; long y; } 
      char* p; 
   } 
} 

Foo f; 

f.i; 
f.x; 
f.y; 
f.p; 


Yapıyı ve değişkeni bir arada tanımlamak

D'de tür ve değişken aynı satırda tanımlanamaz.

C
struct Foo { int x; int y; } foo; 

veya iki satırda

struct Foo { int x; int y; };   // sonda ';' vardir
struct Foo foo; 
D
struct Foo { int x; int y; }    // sonda ';' yoktur
Foo foo;


Yapı üyesinin başlangıçtan uzaklığı [offset]
C
#include <stddef.h>
struct Foo { int x; int y; }; 

uzaklik = offsetof(Foo, y); 
D
struct Foo { int x; int y; } 

uzaklık = Foo.y.offsetof;


Birlik ilkleme

C'de birliğin ilk üyesi ilklenir. D'de ise hangi üyenin ilklendiğinin açıkça belirtilmesi gerekir.

C
union U { int a; long b; }; 
union U x = { 5 };                // 'a' 5'e esitlenir
D
union U { int a; long b; } 
U x = { a:5 };


Yapı ilkleme

C'de üyeler sırayla ilklenirler. Bu kural, küçük yapılarda fazla sorun çıkartmasa da yapı büyüdüğünde sorun haline gelebilir. Özellikle yeni üyelerin araya eklendiği durumlarda kod içinde daha önce yazılmış olan bütün ilkleme ifadelerinin bulunması ve değişiklikten sonra da doğru olarak ilklendiklerine dikkat edilmesi gerekir. D'de ise üyeler açıkça ilklenirler.

C
struct S { int a; int b; }; 
struct S x = { 5, 3 };
D
struct S { int a; int b; } 
S x = { b:3, a:5 };


Dizi ilkleme

C'de diziler değerlerin sırasına göre ilklenirler.

C
int a[3] = { 3,2,2 }; 

İç diziler için { } parantezlerinin kullanımı isteğe bağlıdır.

int b[3][2] = { 2,3, {6,5}, 3,4 }; 
D

D'de ise hem sırayla ilklenebilirler, hem de hangi elemanın ilklendiği açıkça belirtilebilir. Şunların hepsi aynı sonucu verir:

int[3] a = [ 3, 2, 0 ]; 
int[3] a = [ 3, 2 ];          // C'de olduğu gibi, belirtilmeyen
                              // elemanların değeri 0'dır
int[3] a = [ 2:0, 0:3, 1:2 ]; 
int[3] a = [ 2:0, 0:3, 2 ];   // indeks belirtilmediğinde, bir
                              // önceki indeks değerinden devam
                              // edilir

Bu, özellikle dizi indekslerken enum'lar kullanıldığı durumlarda önemlidir.

enum renk { siyah, kırmızı, yeşil }
int[3] c = [ siyah:3, yeşil:2, kırmızı:5 ];

İç dizilerin ilklenmeleri de açıkça belirtilmek zorundadır:

int[2][3] b = [ [2,3], [6,5], [3,4] ]; 

int[2][3] b = [[2,6,3],[3,5,4]];            // hata 


Dizgi sabitlerinde özel karakterler
C

C'de \ karakteri özel karakterleri belirlemek için kullanıldığı için,
c:\klasor\dosya.c gibi bir dosya ismi şöyle belirtilir:

char dosya[] = "c:\\klasor\\dosya.c";

Bu durum düzenli ifadeleri [regexp] daha da karmaşıklaştırır. Örneğin
/"[^\\]*(\\.[^\\]*)*"/ ifadesi için:

char tirnak_icinde[] = "\"[^\\\\]*(\\\\.[^\\\\]*)*\"";
D

D'de ise dizgi içindeki karakterler olmaları gerektiği gibi yazılırlar; özel karakterler ayrı olarak...

char[] dosya = `c:\klasor\dosya.c`; 
char[] tırnak_içinde = r"[^\\]*(\\.[^\\]*)*";


ASCII ve evrensel karakterler

C'de wchar_t türü vardır ve sabit dizgilerin başında L karakteri kullanılır.

C
#include <wchar.h> 
char foo_ascii[] = "merhaba"; 
wchar_t foo_wchar[] = L"merhaba";

Ancak kodun hem ASCII hem de uluslararası karakterlere uyumlu olması istendiğinde makrolardan yararlanmak zorunda kalınır:

#include <tchar.h> 
tchar merhaba[] = TEXT("merhaba");
D

D'de ise ne tür dizgi kullanıldığı koddan anlaşılır.

char[] foo_ascii = "merhaba";   // ascii
wchar[] foo_wchar = "merhaba";  // wchar


enum'ların dizgi karşılıkları
C
enum RENKLER { kirmizi, mavi, yesil, deger_adet }; 
char *dizgiler[deger_adet] = {"kırmızı", "mavi", "yeşil" }; 
D
enum RENKLER { kırmızı, mavi, yeşil }

char[][RENKLER.max + 1] dizgiler = 
[
    RENKLER.kırmızı : "kırmızı",
    RENKLER.mavi    : "mavi", 
    RENKLER.yeşil   : "yeşil",
]; 


typedef'le yeni tür oluşturmak
C

C'de typedef yeni tür oluşturmaz; türe yeni bir isim verir.

typedef void *Cerez;
void foo(void *);
void bar(Cerez);

Cerez h;
foo(h);                        // farkedilmeyen kodlama hatasi
bar(h);                        // dogru kullanim

Böyle hatalardan kurtulmak için tür bir yapı içine alınır:

struct Cerez__ { void *deger; }
typedef struct Cerez__ *Cerez;
void foo(void *);
void bar(Cerez);

Cerez h;
foo(h);                        // simdi derleme hatasi
bar(h);                        // dogru kullanim

Tür için ilk değer atamak için makro tanımlamak, adlandırma yöntemleri geliştirmek, ve kodlamaya dikkat etmek gerekir:

#define CEREZ_ILK ((Cerez)-1)

Cerez h = CEREZ_ILK;
h = fonksiyon();
if (h != CEREZ_ILK)
    ...

Yapı kullanan çözüm daha da karmaşık hale gelir:

struct Cerez__ CEREZ_ILK;

void Cerez_ilk_degeri()        // bu fonksiyon en basta cagrilir
{
    CEREZ_ILK.value = (void *)-1;
}

Cerez h = CEREZ_ILK;
h = fonksiyon();
if (memcmp(&h,&CEREZ_ILK,sizeof(Cerez)) != 0)
    ...
D

typedef yeni tür oluşturduğu için C'deki gibi çözümler gerekmez.

typedef void* Cerez;
void foo(void*);
void bar(Cerez);

Cerez h;
foo(h);
bar(h);

İlklemek de çok daha basittir:

typedef void* Cerez = cast(void*)(-1);
Cerez h;
h = fonksiyon();
if (h != Cerez.init)
    ...


Yapılarda eşitlik karşılaştırması

C'de yapı ataması çok basit olarak derleyici tarafından halledilir, ama eşitlik karşılaştırması için bir yardım gelmez. Bazen kullanılan memcmp ise her durumda çalışmayabilir, çünkü yapı üyeleri arasındaki olası doldurma bitlerinin [padding] hangi değerlerde olacakları standart tarafından tanımlanmamıştır. D'de ise karşılaştırma da atama kadar basittir.

C
#include <string.h>

struct A x, y;
...
x = y;
...
if (memcmp(&x, &y, sizeof(struct A)) == 0)
    ...
D
A x, y;
...
x = y;
...
if (x == y)
    ...


Dizgilerde eşitlik karşılaştırması

C'de dizgiler sonlarındaki '\0' karakteri ile tanımlandıkları için, sonlandırma karakterini bulmayı gerektiren dizi işlemleri doğal olarak yavaştır. D'de ise dizilerin (ve dolayısıyla dizgilerin) uzunlukları da bilindiği için eşitlik karşılaştırmaları çok daha hızlı bir şekilde gerçekleştirilebilir. D ayrıca sıralama karşılaştırmalarını da destekler.

C
char dizgi[] = "merhaba";

if (strcmp(dizgi, "selam") == 0)        // dizgiler esit mi?
    ...
D
char[] dizgi = "merhaba";

if (dizgi == "selam")
    ...

if (dizgi < "selam")
    ...


Dizi sıralamak
C
int karsilastir(const void *p1, const void *p2)
{
    tur *t1 = (tur *)p1;
    tur *t2 = (tur *)p2;

    return *t1 - *t2;
}

type dizi[10];
...
qsort(dizi, sizeof(dizi)/sizeof(dizi[0]),
        sizeof(dizi[0]), karsilastir);
D
type[] dizi;
...
dizi.sort;      // dizi olduğu yerde sıralanır


volatile bellek erişimi

Paylaşımlı bellek veya belleğe bağlı giriş/çıkış gibi işlemlerde karşılaşılan ve değeri derleyici farkında olmadan değişebilen bellek için volatile işaretçiler kulanılabilir. volatile D'de bir deyim türüdür ve deyimi etkiler.

C
volatile int *p = adres;

i = *p;
D
int* p = adres;

volatile { i = *p; }


Sabit dizgiler

C'de sabit dizgiler birden fazla satıra taştığında satır sonlarında \ karakteri gerekir. D'de gerekmez ve böylece başka yerlerden kopyalanan metin, olduğu gibi kullanılabilir.

C
"Bu sabit dizgi\n\
birden fazla\n\
satırda bulunuyor\n"
D
"Bu sabit dizgi
birden fazla
satırda bulunuyor
"


Veri yapılarını ziyaret etmek

Özyinelemeli bir veri yapısındaki elemanları ziyaret eden bir fonksiyon düşünün. Basit bir sembol tablosu olsun. Veri yapısı olarak bir ikili agaç dizisi olsun. Kodun bütün sembollere bakması ve tek olan sembolleri bulması gereksin...

Bu işlem için eleman_ara gibi bir yardımcı fonksiyon gerekir. Bu fonksiyonun ağacın dışında bulunması gereken bir yapıdan bilgi okuması, ve o yapıya bilgi yazması gerekir. Bu bilgi de ElemanBilgisi isimli bir yapıda tutuluyor olsun, ve etkin olması için fonksiyona işaretçi olarak geçirilsin:

C
struct Sembol
{
   char *numara;
   struct Sembol *sol;
   struct Sembol *sag;
};

struct ElemanBilgisi
{
   char *numara;
   struct Sembol *sm;
};

static void eleman_ara(struct ElemanBilgisi *p,
                       struct Sembol *s)
{
   while (s)
   {
      if (strcmp(p->numara,s->numara) == 0)
      {
         if (p->sm)
            error("birden fazla anlamı olan eleman: %s\n",
                   p->numara);
         p->sm = s;
      }

      if (s->sol)
         eleman_ara(p,s->sol);
      s = s->sag;
   }
}

struct Sembol *sembol_ara(Sembol *tablo[],
                          int sembol_adet,
                          char *numara)
{
   struct ElemanBilgisi pb;
   int i;

   pb.numara = numara;
   pb.sm = NULL;
   for (i = 0; i < sembol_adet; i++)
   {
      eleman_ara(pb, tablo[i]);
   }
   return pb.sm;
}
D

Aynı algoritma D'de aşağıdaki gibi yazılabilir. Kapsam fonksiyonları, dıştaki fonksiyondaki nesnelere erişebildikleri için ElemanBilgisi gibi bir türe gerek kalmaz. Yardımcı fonksiyon bütünüyle onu kullanan fonksiyonun içinde tanımlandığı için kod yerelliği açısından önemlidir. C ve D kodları arasında hız bakımından da ölçülebilir bir fark yoktur.

class Sembol
{   char[] numara;
    Sembol sol;
    Sembol sağ;
}

Sembol sembol_ara(Sembol[] tablo, char[] numara)
{   Sembol sm;

    void eleman_ara(Sembol s)
    {
        while (s)
        {
            if (numara == s.numara)
            {
                if (sm)
                    error(
                       "birden fazla anlamı olan eleman: %s\n",
                       numara );
                sm = s;
            }

            if (s.sol)
                eleman_ara(s.sol);
            s = s.sağ;
        }
    }

    for (int i = 0; i < tablo.length; i++)
    {
        eleman_ara(tablo[i]);
    }
    return sm;
}


İşaretsiz sayılarda sağa kaydırma
C

Sağa kaydırma işleçleri >> ve >>=, işlemlerini sol tarafın türüne göre ya işaretli olarak ya da işaretsiz olarak yaparlar. Türün int olduğu durumda da işaretsiz bir sonuç elde etmek için tür değişimi kullanmak gerekir:

int i, j;
...
j = (unsigned)i >> 3;

Sağa kaydırılan bir int ise bu doğru çalışır, ama örneğin typedef yoluyla gizlenmiş bir long ise, üst bitlerin farkında olunmadan kaybedilme riski doğar:

benim_int i, j;
...
j = (unsigned)i >> 3;
D

>> ve >>= işleçleri D'de de aynı şekilde çalışırlar, ama D'de kaydırmayı tür ne olursa olsun işaretsiz olarak yapan >>> ve >>>= işleçleri de vardır:

benim_int i, j;
...
j = i >>> 3;


Dinamik kapamalar [closures]
C

Esnek bir topluluk veri yapısı düşünün. Esnek kabul edilebilmesi için, dışarıdan verilen bir fonksiyonu elemanların hepsine teker teker uygulasın. Bunu, ismi uygula olan ve bir fonksiyon işaretçisi yanında bir de topluluktaki elemanlardan birisini alan bir fonksiyon olarak düşünebiliriz.

Ek olarak, yapılan işle ilgili bilgi tutmak için ve o bilginin türü esnek olabilsin diye void* bir de kapsam yapısı alması gerekir. Bu örnekte int'lerden oluşan bir topluluk, ve o topluluktaki en büyük elemanı bulmaya çalışan bir kullanıcı kodu var:

void uygula(
      void *p, int *dizi, int uzunluk, void (*fp)(void *, int))
{
    for (int i = 0; i < uzunluk; i++)
        fp(p, dizi[i]);
}

struct Topluluk
{
    int dizi[10];
};

void en_buyugunu_bul(void *p, int i)
{
    int *p_en_buyuk = (int *)p;

    if (i > *p_en_buyuk)
        *p_en_buyuk = i;
}

void fonksiyon(struct Topluluk *t)
{
    int en_buyuk = INT_MIN;

    uygula(&en_buyuk,
           t->dizi, sizeof(t->dizi)/sizeof(t->dizi[0]),
           en_buyugunu_bul);
}
D

D'de ise işle ilgili bilgiyi aktarmak için temsilcilerden [delegate], kapsam içindeki bilgiye erişebilmek ve yerelliği arttırmak için de kapsam fonksiyonlarından yararlanılır. Tür dönüşümlerine gerek kalmadığı için, onların getireceği olası hatalar da ortadan kalkmış olur:

class Topluluk
{
    int[10] dizi;

    void uygula(void delegate(int) fp)
    {
        for (int i = 0; i < dizi.length; i++)
            fp(dizi[i]);
    }
}

void fonksiyon(Topluluk c)
{
    int en_buyuk = int.min;

    void en_buyugunu_bul(int i)
    {
        if (i > en_buyuk)
            en_buyuk = i;
    }

    c.uygula(en_buyugunu_bul);
}

Başka bir yöntem ise fonksiyon sabiti kullanmaktır; böylece gereksiz fonksiyon isimleri bulmak da gerekmemiş olur:

void fonksiyon(Topluluk t)
{
    int en_buyuk = int.min;

    t.uygula(
         delegate(int i) { if (i > en_buyuk) en_buyuk = i; } );
}


Belirsiz sayıda fonksiyon parametreleri

Kaç tane oldukları baştan bilinmeyen parametrelerinin hepsinin toplamını bulan bir fonksiyon yazmaya çalışalım.

C
#include <stdio.h>
#include <stdarg.h>

int toplam(int uzunluk, ...)
{   int i;
    int t = 0;
    va_list ap;

    va_start(ap, uzunluk);
    for (i = 0; i < uzunluk; i++)
        t += va_arg(ap, int);
    va_end(ap);
    return t;
}

int main()
{
    int i;

    i = toplam(3, 8,7,6);
    printf("toplam = %d\n", i);

    return 0;
} 

Bunda iki sorun vardır: Birincisi, toplam fonksiyonuna kaç tane sayı olduğunun bildirilmesi gerekir; ikincisi, gönderilen parametrelerin gerçekten int olup olmadıklarını anlamanın hiçbir yolu yoktur.

D

Dizi türündeki bir parametreyi izleyen ... karakterleri, o diziden sonra gelen bütün parametrelerin o dizinin elemanları olarak sunulacaklarını belirler. Parametrelerin gerçekten dizinin türüne uyup uymadıkları denetlenir, ve kaç tane parametre bulunduğu dizinin length niteliğinden anlaşılabilir:

import std.stdio;

int toplam(int[] değerler ...)
{
    int t = 0;

    foreach (int x; değerler)
        t += x;
    return t;
}

int main()
{
    int i;

    i = toplam(8,7,6);
    writefln("toplam = %d", i);

    return 0;
}