Thread overview
Soru: CTFE Olayları!
Apr 15, 2022
Salih Dincer
Apr 15, 2022
Ali Çehreli
Apr 15, 2022
Salih Dincer
April 15, 2022

Merhaba,

Aşağıdaki kod CTFE (Compile Time Function Execution) kapsamında derlenir. Ama merak ettiğim bir şey var. Bu kod içindeki işlev an itibariyle %100 static mi? Yani ben main() dışında çağırmak ile derleme zamanında işletildiği garantisini verebir miyim?

auto genFactorials(int n)
{
  auto result = new int[n];
    result[0] = 1;
    foreach (i; 1 .. n)
    {
    	result[i] = result[i - 1] * i;
    }
  return result;
}

  enum factorials = genFactorials(13);
  enum fact13th =  479001600;

void main()
{
  static assert(factorials.length == 13);
  static assert(factorials[$-1] == fact13th);
}

Bir soru daha, diyelim ki main() içinde runtime çağırdım. Bu durumda kodun gerçekten programa dahil edildiği sonucu çıkarabilir miyiz? Örneğin hepsini bir stack içine attım ve sonra kareköklerini aldım.

Teşekkürler...

April 15, 2022
On 4/15/22 07:19, Salih Dincer wrote:

> Aşağıdaki kod CTFE (Compile Time Function Execution) kapsamında
> derlenir.

Bir değer (genel olarak "ifade (expression)") derleme zamanında gerektiğinde derleme zamanında işletilir. (İşletilmesi için gerekenler derleme zamanında mevcut değilse işletilemez ve derleme hatasıdır.)

> Ama merak ettiğim bir şey var. Bu kod içindeki işlev an
> itibariyle %100 static mi?

İşlev static değil, çağrıldığında döndürülen değer static. (Bir işlevin kodları işletilecek biçimde derlenmemiş olabilir ama o konu derleyicinin eniyileştirme yeteneği ile ilgilidir.)

> Yani ben main() dışında çağırmak

CTFE'nin main içinde veya dışında çağrılmakla tarif edilmemeli. (Sen bu örnek için söylüyorsun.)

> ile derleme
> zamanında işletildiği garantisini verebir miyim?

Garanti, o değerin derleme zamanında gerekmiş olmasıdır.

> ```d
> auto genFactorials(int n)
> {
>    auto result = new int[n];
>      result[0] = 1;
>      foreach (i; 1 .. n)
>      {
>          result[i] = result[i - 1] * i;
>      }
>    return result;
> }

Bir derleyici, karşısına çıkan işlevleri sıra ile derliyor olabilir. Evet, genFactorials() çalışma zamanında (da) işletilecek biçimde koda eklenecektir.

>    enum factorials = genFactorials(13);

D'de 'enum' sabit değer (manifest constant) anlamına gelir. O değerin derleme zamanında bilinmesi gerektiğinden genFactorials() derleme zamanında işletilecektir. (Eğer derleyici işlevin derlenmesini bu noktaya geciktirdiyse bu artık noktada kesin derleyecektir.)

>    enum fact13th =  479001600;

Orada zaten salt bir 'int' değer kullanılıyor.

Derleme zamanında işletilmeyi gerektiren durumlar şunlardır (bazılarını unutuyor olabilir):

- enum değerler

- static const değerler

- Şablon parametreleri

- static if

- static assert

- static foreach

- version değeri

- debug değeri

Yani, derleme zamanında gereken herşey.

> void main()
> {
>    static assert(factorials.length == 13);

'factorials.length' derleme zamanında hesaplanır ve 13 sabit değerinin aynısıdır.

>    static assert(factorials[$-1] == fact13th);

factorials[$-1] derleme zamanında şu ifade olarak işletilir: *(factorials.ptr + factorials.length - 1). Ama ürettiği değer 479001600'nın aynısıdır.

> }
> ```
> Bir soru daha, diyelim ki main() içinde runtime çağırdım.

Örneğin:

void main(string[] args) {
  genFactorials(args.length);
}

> Bu durumda
> kodun gerçekten programa dahil edildiği sonucu çıkarabilir miyiz?
> Örneğin hepsini bir stack içine attım ve sonra kareköklerini aldım.

D gibi dillerde "separate compilation" diye bir kavram var: Programın parçaları ayrı ayrı derlenmiş olabilir. Buna göre, örneğin programın ilk derlenmiş parçası daha sonradan derlenmiş bir parçasını çağırıyor olabilir. (İkinci kodun tek ihtiyacı, birinci işlevin ilintisidir (D binding).) Dolayısıyla, hiçbir derleme işlevin programa dahil edilmemesi kararını veremez.

Böyle bir kararı ancak programı en sonunda oluşturacak olan bağlayıcı (linker) verebilir. O da galiba bağlayıcıya göre değişebilir veya kullanılan bağlayıcı seçenekleri önemlidir. Emin değilim...

Ben nadir de olsa bu gibi konularda iki araç kullanıyorum:

- Dissassembler: İnternette bir kaç site olabildiği gibi objdump, obj2asm, vs. gibi bir program da olabilir.

- nm: Program parçaları (.o, .lib, vs. dosyaları) veya programlar içinde bulununan semboller ile ilgili bilgi verir.

1) Programı derliyorum:

  $ dmd deneme.d

2) Derleyicinin oluşturduğu kodlara bakıyorum:

  $ objdump -d deneme > deneme.asm

_Dmain işlevi bomboş:

  00000000000457bc <_Dmain>:
   457bc:	31 c0                	xor    %eax,%eax

                                                  eax yazmacını
                                                  kendisi ile xor
                                                  yaparak 0 üretiyor
                                                  (başarılı sonuçlanma
                                                  anlamında)

   457be:	c3                   	ret    dış dünyaya dönüyor

Program içinde ne 'factorials' var ne de 'fact13th'.

Ama yine de programın içinde genFactorials() diye bir işlev var:

00000000000456ec <_D6deneme13genFactorialsFNaNbNfiZAi>:
   456ec:	55                   	push   %rbp
   456ed:	48 8b ec             	mov    %rsp,%rbp
   456f0:	48 83 ec 30          	sub    $0x30,%rsp

                                              rsp, son sohbette
                                              konuştuğumuz
                                              "stack pointer"

   // ...

   457b8:	c9                   	leave
   457b9:	c3                   	ret

(extern(C) diye derlenseydi işlevin ismi genFactorials() olurdu. Bu konu işlev yüklemeyi (overloading) desteklemek için gereken "name mangling" ile ilgilidir.)

3) Şimdi de nm ile bakalım:

  $ nm deneme | grep genFactorials
  00000000000456dc W _D6deneme13genFactorialsFNaNbNfiZAi

Evet, programda o sembol varmış ve 'W' imiş. nm'in belgesine 'man nm' diye baktığımızda W'nun anlamının "weak symbol" olduğunu görürüz. Yani, burada tanımlanmış ama başka bir program parçası veya kütüphane tarafından aynı sembol (isim) normal olarak tanımlanmışsa, bağlayıcı normal tanımı kullanacak demektir.

Ali

April 15, 2022

On Friday, 15 April 2022 at 17:09:52 UTC, Ali Çehreli wrote:

>

On 4/15/22 07:19, Salih Dincer wrote:

>

Aşağıdaki kod CTFE (Compile Time Function Execution)
kapsamında
derlenir.

Bir değer (genel olarak "ifade (expression)") derleme zamanında gerektiğinde derleme zamanında işletilir. (İşletilmesi için gerekenler derleme zamanında mevcut değilse işletilemez ve derleme hatasıdır.)

>

Ama merak ettiğim bir şey var. Bu kod içindeki işlev an
itibariyle %100 static mi?

İşlev static değil, çağrıldığında döndürülen değer static. (Bir işlevin kodları işletilecek biçimde derlenmemiş olabilir ama o konu derleyicinin eniyileştirme yeteneği ile ilgilidir.)

[...]

Biraz daha deneme yapmam (anlamam için) lazım ama çok güzel bir anlatım. Yine de sorularım olabilir, çok teşekkür ederim.

SDB@79