Pragmalar
Pragma derleyiciyle etkileşme yöntemlerinden birisidir. Hem derleyiciye bilgi vermeye hem de ondan bilgi almaya yarar. Pragmalar şablonlardan başka kodlarda yararlı olsalar da, özellikle pragma(msg)
şablonların hatalarını ayıklarken kullanışlıdır.
Her derleyici kendi özel pragmalarını tanımlayabilir ama aşağıdaki pragmalar standarttır:
pragma(msg)
Derleme zamanında stderr
çıkış akımına mesaj yazdırmaya yarar; çalışma zamanına bir etkisi yoktur.
Örneğin, aşağıdaki pragma(msg)
bir işlev şablonunun tam olarak hangi parametrelerle çağrıldığını bildirmektedir:
import std.string; void işlev(A, B)(A a, B b) { pragma(msg, format("Şablon parametreleri: '%s' ve '%s'", A.stringof, B.stringof)); // ... } void main() { işlev(42, 1.5); işlev("merhaba", 'a'); }
Şablon parametreleri: 'int' ve 'double' Şablon parametreleri: 'string' ve 'char'
pragma(lib)
Programın bağlanması gereken kütüphaneleri bildirmek için kullanılır. Programı sistemde kurulu olan bir kütüphaneyle bağlamanın en kolay yolu budur.
Örneğin, curl
kütüphanesini kullanan aşağıdaki program kütüphaneyi derleme satırında belirtmek gerekmeden oluşturulabilir:
import std.stdio; import std.net.curl; pragma(lib, "curl"); void main() { // Kitabın bu bölümünü indirmek: writeln(get("ddili.org/ders/d/pragma.html")); }
pragma(inline)
İşlev içeriğinin kod içine açılıp açılmayacağını belirler.
Her işlev çağrısının bir masrafı vardır. Bu masraf, işlevin varsa parametrelerinin kopyalanmaları, varsa dönüş değerinin çağırana döndürülmesi, ve sonlandıktan sonra hangi noktadan devam edileceğinin hesabının tutulması ile ilgilidir.
Bu masraf çoğu durumda işlevin kendisinin ve çağıran tarafın diğer işlemlerinin masrafları yanında dikkate alınmayacak kadar küçüktür. Ancak, bazı durumlarda salt işlev çağrısı bile programın hızını ölçülebilir derecede yavaşlatabilir. Bu, özellikle işlev içeriğinin göreceli olarak hızlı olduğu ve yine göreceli olarak küçük bir döngüden çok sayıda çağrıldığı durumlarda görülebilir.
Aşağıdaki program küçük bir işlevi yine küçük bir döngü içinden çağırmakta ve bir sayacın değerini işlevin dönüş değerine bağlı olarak arttırmaktadır:
import std.stdio; import std.datetime.stopwatch; // Oldukça hızlı bir işlev içeriği: ubyte hesapla(ubyte i) { return cast(ubyte)(i * 42); } void main() { size_t sayaç = 0; StopWatch kronometre; kronometre.start(); // Çok sayıda tekrarlanan küçük bir döngü: foreach (i; 0 .. 100_000_000) { const parametre = cast(ubyte)i; if (hesapla(parametre) == parametre) { ++sayaç; } } kronometre.stop(); writefln("%s milisaniye", kronometre.peek.total!"msecs"); }
Bu program döngünün ne kadar sürede işletildiğini std.datetime.stopwatch.StopWatch
ile ölçmektedir:
674 milisaniye
-inline
derleyici seçeneği, işlev içeriklerinin kod içine açılmalarına dayanan bir eniyileştirmeyi etkinleştirir:
$ dmd deneme.d -w -inline
İşlevin kod içine açılması, içeriğinin çağrıldığı noktaya sanki oraya elle yazılmış gibi yerleştirilmesi anlamına gelir. Yukarıdaki döngü bu eniyileştirme uygulandığında aşağıdaki eşdeğeri gibi derlenecektir:
// Döngünün hesapla()'nın kod içine açıldığındaki eşdeğeri: foreach (i; 0 .. 100_000_000) { const parametre = cast(ubyte)i; const sonuç = cast(ubyte)(parametre * 42); if (sonuç == parametre) { ++sayaç; } }
Bu işlev çağrısının böylece ortadan kalkması programı denediğim ortamda %40 kadar bir zaman kazancı sağlamaktadır:
407 milisaniye
İşlevlerin kod içine açılmaları her ne kadar büyük bir kazanç gibi görünse de, bu eniyileştirme her duruma uygun değildir çünkü açılan işlevler kodun fazla büyümesine ve mikro işlemcinin kod ön belleğinden taşmasına neden olabilir. Bunun sonucunda da kod tam tersine daha yavaş işleyebilir. Bu yüzden, işlevlerin kod içine açılmalarının kararı normalde -inline
seçeneği ile derleyiciye bırakılır.
Buna rağmen, bazı durumlarda derleyiciye bu konudaki kararında yardım edilmesi yararlı olabilir. inline
pragması bu amaçla kullanılır:
pragma(inline, false)
:-inline
derleyici seçeneği kullanılmış bile olsa belirli işlevlerin kod içine açılmamaları gerektiğini bildirir.pragma(inline, true)
:-inline
derleyici seçeneği kullanıldığında belirli işlevlerin kesinlikle kod içine açılmaları gerektiğini bildirir. Bu eniyileştirmenin uygulanamadığı durumlarda derleme hataları oluşur. (Buna rağmen, bu pragmanın tam olarak nasıl işlediği derleyiciden derleyiciye değişebilir.)pragma(inline)
: Kod içine açma kararını-inline
seçeneğinin komut satırında belirtilmiş veya belirtilmemiş olmasına göre tekrar derleyiciye bırakır.
Bu pragmalar, içinde geçtikleri işlevi etkileyebildikleri gibi, birden fazla işlev üzerinde etkili olabilmek için kapsam parantezleriyle veya iki nokta üst üste karakteriyle de kullanılabilirler:
pragma(inline, false) { // Bu kapsamda tanımlanan işlevler kod içine açılmazlar // ... } int foo() { pragma(inline, true); // Bu işlev kod içine açılmalıdır // ... } pragma(inline, true): // Bu bölümde tanımlanan işlevler kod içine açılmalıdırlar // ... pragma(inline): // Bu bölümde tanımlanan işlevlerin kod içine açılıp // açılmayacaklarının kararı tekrar derleyici bırakılmıştır // ...
Programların daha hızlı işlemelerini sağlayan bir başka derleyici seçeneği -O
'dur. Bu seçenek derleyicinin başka eniyileştirme algoritmaları işletmesini sağlar. Ancak, bunun sonucunda derleme süreleri fazla uzayabilir.
pragma(startaddress)
Programın başlangıç adresini belirtmeye yarar. Başlangıç adresi zaten D'nin çalışma ortamı tarafından belirlendiğinden normalde bu pragmaya gerek olmaz.
pragma(mangle)
Özgün isim üretirken normal yöntemle üretilecek olandan farklı bir isim kullanılmasını belirler. Özgün isimler bağlayıcının işlevleri ve o işlevleri çağıranları tanıyabilmesi için önemlidir. Bu pragma özellikle D kodunun tesadüfen bir anahtar sözcüğe karşılık gelen bir kütüphane işlevini çağırması gereken durumlarda yararlıdır.
Örneğin, override
bir D anahtar sözcüğü olduğundan bir C kütüphanesinin override
ismindeki bir işlevi D kodundan çağrılamaz. İşlevin farklı bir isimle çağrılması ama yine de kütüphanenin override
isimli işlevine bağlanması gerekir:
/* Bir C kütüphanesinin 'override' ismindeki işlevi ancak * 'c_override' gibi bir isimle çağrılabilir. Ancak, bu isim * yine de 'override' olarak bağlanmalıdır: */ pragma(mangle, "override") extern(C) string c_override(string); void main() { /* D kodu işlevi c_override() diye çağırır ama bağlayıcı * yine de doğru ismi olan 'override'ı kullanacaktır: */ auto s = c_override("merhaba"); }