<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://program.sonsuz.us/feed.xml" rel="self" type="application/atom+xml" /><link href="https://program.sonsuz.us/" rel="alternate" type="text/html" /><updated>2026-10-20T06:05:40+00:00</updated><id>https://program.sonsuz.us/feed.xml</id><title type="html">SonsuzUs</title><subtitle>Programlama ve Yazılım</subtitle><author><name>Sonsuz Us</name></author><entry><title type="html">C# ile Multithreading: TPL, Task ve async/await Rehberi</title><link href="https://program.sonsuz.us/posts/c-ile-multithreading-tpl-task-ve-asyncawait-rehberi/" rel="alternate" type="text/html" title="C# ile Multithreading: TPL, Task ve async/await Rehberi" /><published>2026-10-20T00:00:00+00:00</published><updated>2026-10-20T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/c-ile-multithreading-tpl-task-ve-asyncawait-rehberi</id><content type="html" xml:base="https://program.sonsuz.us/posts/c-ile-multithreading-tpl-task-ve-asyncawait-rehberi/"><![CDATA[<p>Bir uygulamanın aynı anda birden fazla iş yapabilmesi kulağa sihir gibi gelebilir; ancak C# dünyasında bu sihrin arkasında iş parçacıkları, görevler ve dikkatli bir zamanlama mekanizması bulunur. Task Parallel Library (TPL) CPU ağırlıklı işleri paralelleştirirken <code class="language-plaintext highlighter-rouge">async/await</code>, özellikle dosya, ağ ve veritabanı gibi beklemeli işlemlerde iş parçacıklarını gereksiz yere meşgul etmeden ölçeklenebilir uygulamalar kurmamızı sağlar.
``</p>
<h2 id="eşzamanlılık-ve-paralellik-aynı-şey-değildir">Eşzamanlılık ve paralellik aynı şey değildir</h2>

<p>Eşzamanlılık, birden fazla işin zaman aralıkları iç içe geçecek şekilde ilerlemesidir. Paralellik ise bu işlerin gerçekten aynı anda, örneğin farklı işlemci çekirdeklerinde çalışmasıdır.</p>

<table>
  <thead>
    <tr>
      <th>Kavram</th>
      <th>Temel amaç</th>
      <th>Uygun iş türü</th>
      <th>C# aracı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Eşzamanlılık</td>
      <td>Beklerken başka işe geçmek</td>
      <td>Ağ, dosya, veritabanı</td>
      <td><code class="language-plaintext highlighter-rouge">async/await</code></td>
    </tr>
    <tr>
      <td>Paralellik</td>
      <td>Hesabı çekirdeklere dağıtmak</td>
      <td>Görüntü işleme, hesaplama</td>
      <td><code class="language-plaintext highlighter-rouge">Parallel</code>, TPL</td>
    </tr>
    <tr>
      <td>İş parçacığı</td>
      <td>Çalıştırma kaynağı sağlamak</td>
      <td>Düşük seviyeli kontrol</td>
      <td><code class="language-plaintext highlighter-rouge">Thread</code></td>
    </tr>
    <tr>
      <td>Görev</td>
      <td>Yapılacak işi temsil etmek</td>
      <td>Modern iş akışları</td>
      <td><code class="language-plaintext highlighter-rouge">Task</code></td>
    </tr>
  </tbody>
</table>

<p>Bir işin tek çekirdekte tamamlanma süresi $T_1$, $p$ çekirdekteki süresi $T_p$ ise teorik hızlanma şöyle ifade edilir:</p>

\[S_p = \frac{T_1}{T_p}\]

<p>İdeal durumda $S_p \approx p$ beklenir. Gerçekte görev oluşturma maliyeti, senkronizasyon ve paylaşılan kaynaklar nedeniyle bu değere nadiren ulaşılır.</p>

<h2 id="tpl-ile-cpu-ağırlıklı-işleri-çalıştırmak">TPL ile CPU ağırlıklı işleri çalıştırmak</h2>

<p>TPL, görevlerin uygun iş parçacıklarına dağıtılmasını <code class="language-plaintext highlighter-rouge">ThreadPool</code> üzerinden yönetir. Böylece her iş için elle <code class="language-plaintext highlighter-rouge">Thread</code> oluşturmak gerekmez.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">System</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.Linq</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.Threading.Tasks</span><span class="p">;</span>

<span class="kt">int</span><span class="p">[]</span> <span class="n">sayilar</span> <span class="p">=</span> <span class="n">Enumerable</span><span class="p">.</span><span class="nf">Range</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">8</span><span class="p">).</span><span class="nf">ToArray</span><span class="p">();</span>

<span class="n">Parallel</span><span class="p">.</span><span class="nf">ForEach</span><span class="p">(</span><span class="n">sayilar</span><span class="p">,</span> <span class="n">sayi</span> <span class="p">=&gt;</span>
<span class="p">{</span>
    <span class="kt">double</span> <span class="n">sonuc</span> <span class="p">=</span> <span class="n">Math</span><span class="p">.</span><span class="nf">Sqrt</span><span class="p">(</span><span class="n">sayi</span><span class="p">)</span> <span class="p">*</span> <span class="n">Math</span><span class="p">.</span><span class="nf">Pow</span><span class="p">(</span><span class="n">sayi</span><span class="p">,</span> <span class="m">3</span><span class="p">);</span>
    <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">$"</span><span class="p">{</span><span class="n">sayi</span><span class="p">}</span><span class="s">: </span><span class="p">{</span><span class="n">sonuc</span><span class="p">}</span><span class="s"> - Thread: </span><span class="p">{</span><span class="n">Environment</span><span class="p">.</span><span class="n">CurrentManagedThreadId</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
<span class="p">});</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">Parallel.ForEach</code>, koleksiyondaki hesaplamaları mümkün olduğunda farklı iş parçacıklarında yürütür. Ancak çok küçük işlemleri paralelleştirmek, yönetim maliyeti yüzünden normal bir döngüden daha yavaş olabilir. Önce ölçmek, sonra paralelleştirmek altın kuraldır.</p>

<p>Bağımsız görevleri başlatıp hepsinin bitmesini beklemek için <code class="language-plaintext highlighter-rouge">Task.WhenAll</code> kullanılabilir:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Task</span><span class="p">&lt;</span><span class="kt">int</span><span class="p">&gt;</span> <span class="n">hesap1</span> <span class="p">=</span> <span class="n">Task</span><span class="p">.</span><span class="nf">Run</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="n">Enumerable</span><span class="p">.</span><span class="nf">Range</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">1_000_000</span><span class="p">).</span><span class="nf">Sum</span><span class="p">());</span>
<span class="n">Task</span><span class="p">&lt;</span><span class="kt">int</span><span class="p">&gt;</span> <span class="n">hesap2</span> <span class="p">=</span> <span class="n">Task</span><span class="p">.</span><span class="nf">Run</span><span class="p">(()</span> <span class="p">=&gt;</span> <span class="n">Enumerable</span><span class="p">.</span><span class="nf">Range</span><span class="p">(</span><span class="m">1</span><span class="p">,</span> <span class="m">500_000</span><span class="p">).</span><span class="nf">Sum</span><span class="p">());</span>

<span class="kt">int</span><span class="p">[]</span> <span class="n">sonuclar</span> <span class="p">=</span> <span class="k">await</span> <span class="n">Task</span><span class="p">.</span><span class="nf">WhenAll</span><span class="p">(</span><span class="n">hesap1</span><span class="p">,</span> <span class="n">hesap2</span><span class="p">);</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">$"Toplam: </span><span class="p">{</span><span class="n">sonuclar</span><span class="p">.</span><span class="nf">Sum</span><span class="p">()}</span><span class="s">"</span><span class="p">);</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">Task.Run</code>, CPU ağırlıklı senkron kodu ThreadPool üzerinde çalıştırır. Buna karşılık zaten asenkron olan HTTP veya veritabanı çağrılarını ayrıca <code class="language-plaintext highlighter-rouge">Task.Run</code> içine koymak genellikle gereksizdir.</p>

<h2 id="asyncawait-ile-beklerken-kaynak-tüketmemek">async/await ile beklerken kaynak tüketmemek</h2>

<p><code class="language-plaintext highlighter-rouge">async</code>, metodun asenkron işlem içerebildiğini; <code class="language-plaintext highlighter-rouge">await</code> ise işlem tamamlanana kadar kontrolün çağırana geri verilebileceğini belirtir. Bu sırada iş parçacığının bloklanması gerekmez.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">System.Net.Http</span><span class="p">;</span>

<span class="k">static</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="kt">int</span><span class="p">&gt;</span> <span class="nf">SayfaBoyutuAsync</span><span class="p">(</span>
    <span class="kt">string</span> <span class="n">adres</span><span class="p">,</span>
    <span class="n">CancellationToken</span> <span class="n">iptal</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">using</span> <span class="nn">HttpClient</span> <span class="n">istemci</span> <span class="p">=</span> <span class="k">new</span><span class="p">();</span>
    <span class="kt">string</span> <span class="n">icerik</span> <span class="p">=</span> <span class="k">await</span> <span class="n">istemci</span><span class="p">.</span><span class="nf">GetStringAsync</span><span class="p">(</span><span class="n">adres</span><span class="p">,</span> <span class="n">iptal</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">icerik</span><span class="p">.</span><span class="n">Length</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">using</span> <span class="nn">CancellationTokenSource</span> <span class="n">kaynak</span> <span class="p">=</span> <span class="k">new</span><span class="p">();</span>
<span class="n">kaynak</span><span class="p">.</span><span class="nf">CancelAfter</span><span class="p">(</span><span class="n">TimeSpan</span><span class="p">.</span><span class="nf">FromSeconds</span><span class="p">(</span><span class="m">5</span><span class="p">));</span>

<span class="k">try</span>
<span class="p">{</span>
    <span class="kt">int</span> <span class="n">boyut</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">SayfaBoyutuAsync</span><span class="p">(</span><span class="s">"https://example.com"</span><span class="p">,</span> <span class="n">kaynak</span><span class="p">.</span><span class="n">Token</span><span class="p">);</span>
    <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">$"İndirilen karakter: </span><span class="p">{</span><span class="n">boyut</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">catch</span> <span class="p">(</span><span class="n">OperationCanceledException</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">"İşlem iptal edildi."</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Buradaki <code class="language-plaintext highlighter-rouge">CancellationToken</code>, uzun süren işlemin kontrollü biçimde durdurulmasını sağlar. <code class="language-plaintext highlighter-rouge">await</code> edilen görev hata üretirse istisna normal bir senkron metottaki gibi <code class="language-plaintext highlighter-rouge">try/catch</code> ile yakalanabilir.</p>

<h2 id="paylaşılan-veriler-ve-yarış-durumları">Paylaşılan veriler ve yarış durumları</h2>

<p>Birden fazla görev aynı değişkeni değiştirirse sonuç öngörülemez olabilir. Örneğin <code class="language-plaintext highlighter-rouge">sayac++</code> atomik değildir; okuma, artırma ve yazma adımlarından oluşur. Güvenli artırma için <code class="language-plaintext highlighter-rouge">Interlocked.Increment(ref sayac)</code> veya daha karmaşık kritik bölgelerde <code class="language-plaintext highlighter-rouge">lock</code> kullanılmalıdır.</p>

<p>Modern C# kodunda temel yaklaşım basittir: I/O ağırlıklı işlemlerde doğal asenkron API’leri <code class="language-plaintext highlighter-rouge">await</code> edin, CPU ağırlıklı ve bağımsız hesaplamalarda TPL kullanın, paylaşılan durumu azaltın ve performans kararlarını mutlaka ölçümlerle doğrulayın.</p>

<p><img src="/img/c-ile-multithreading-31.svg" alt="c-ile-multithreading-31" /></p>]]></content><author><name>Sonsuz Us</name></author><category term="Program" /><category term="csharp" /><category term="multithreading" /><category term="tpl" /><category term="async" /><category term="await" /><category term="paralel-programlama" /><summary type="html"><![CDATA[Bir uygulamanın aynı anda birden fazla iş yapabilmesi kulağa sihir gibi gelebilir; ancak C# dünyasında bu sihrin arkasında iş parçacıkları, görevler ve dikkatli bir zamanlama mekanizması bulunur. Task Parallel Library (TPL) CPU ağırlıklı işleri paralelleştirirken async/await, özellikle dosya, ağ ve veritabanı gibi beklemeli işlemlerde iş parçacıklarını gereksiz yere meşgul etmeden ölçeklenebilir uygulamalar kurmamızı sağlar.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/c-ile-multithreading-31.png" /><media:content medium="image" url="https://program.sonsuz.us/img/c-ile-multithreading-31.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">C++ STL’de Iterator Geçersizliği: erase Tuzağından Güvenle Kaçış</title><link href="https://program.sonsuz.us/posts/c-stlde-iterator-gecersizligi-erase-tuzagindan-guvenle-kacis/" rel="alternate" type="text/html" title="C++ STL’de Iterator Geçersizliği: erase Tuzağından Güvenle Kaçış" /><published>2026-10-20T00:00:00+00:00</published><updated>2026-10-20T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/c-stlde-iterator-gecersizligi-erase-tuzagindan-guvenle-kacis</id><content type="html" xml:base="https://program.sonsuz.us/posts/c-stlde-iterator-gecersizligi-erase-tuzagindan-guvenle-kacis/"><![CDATA[<p>Bir STL konteynerinde dolaşırken eleman silmek, ilk bakışta son derece masum görünür. Ancak yanlış kullanılan tek bir <code class="language-plaintext highlighter-rouge">erase</code>, yineleyiciyi geçersiz hâle getirerek tanımsız davranışa, atlanan elemanlara veya yalnızca cuma akşamları ortaya çıkan gizemli çökmelere neden olabilir. Bu tuzağın kaynağı, her konteynerin elemanlarını bellekte farklı biçimde saklamasıdır.</p>

<p>``</p>

<h2 id="iterator-neden-geçersiz-olur">Iterator neden geçersiz olur?</h2>

<p>Iterator, çoğu zaman bir elemana ulaşmayı sağlayan adres benzeri bir nesnedir. Bir eleman silindiğinde konteyner, belleğini yeniden düzenleyebilir. Iterator artık yaşayan bir elemana işaret etmiyorsa onu karşılaştırmak, artırmak veya dereference etmek güvenli değildir.</p>

<p>Örneğin <code class="language-plaintext highlighter-rouge">vector</code>, elemanlarını ardışık bellekte tutar. İndisi $i$ olan eleman silindiğinde arkasındaki yaklaşık</p>

\[n-i-1\]

<p>eleman sola taşınır. Böylece silinen elemanı ve sonrasını gösteren iterator’lar geçersizleşir. İşlemin zaman karmaşıklığı da bu taşıma nedeniyle genel olarak $O(n)$ olur.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">sayilar</span><span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">};</span>
<span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">sayilar</span><span class="p">.</span><span class="n">begin</span><span class="p">()</span> <span class="o">+</span> <span class="mi">2</span><span class="p">;</span> <span class="c1">// 3</span>

<span class="n">sayilar</span><span class="p">.</span><span class="n">erase</span><span class="p">(</span><span class="n">it</span><span class="p">);</span>
<span class="c1">// it artık geçersizdir!</span>
<span class="c1">// std::cout &lt;&lt; *it; // Tanımsız davranış</span>
</code></pre></div></div>

<p>Buradaki yaygın yanılgı, <code class="language-plaintext highlighter-rouge">it</code> değişkeninin otomatik olarak sıradaki elemana geçeceğini düşünmektir. Oysa <code class="language-plaintext highlighter-rouge">erase</code>, eski iterator’ı onarmaz; bunun yerine geçerli olan sonraki iterator’ı döndürür.</p>

<h2 id="güvenli-silme-deseni">Güvenli silme deseni</h2>

<p>Dolaşma sırasında silme yapılacaksa <code class="language-plaintext highlighter-rouge">erase</code> dönüş değeri kullanılmalıdır:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">sayilar</span><span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">};</span>

<span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">sayilar</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span> <span class="n">it</span> <span class="o">!=</span> <span class="n">sayilar</span><span class="p">.</span><span class="n">end</span><span class="p">();</span> <span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">*</span><span class="n">it</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">it</span> <span class="o">=</span> <span class="n">sayilar</span><span class="p">.</span><span class="n">erase</span><span class="p">(</span><span class="n">it</span><span class="p">);</span> <span class="c1">// Sonraki geçerli konumu al</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="o">++</span><span class="n">it</span><span class="p">;</span>                   <span class="c1">// Yalnızca silinmediyse ilerle</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Döngünün üçüncü bölümü özellikle boş bırakılmıştır. Hem <code class="language-plaintext highlighter-rouge">erase</code> sonrasında hem de döngü sonunda <code class="language-plaintext highlighter-rouge">++it</code> çalıştırılsaydı bir eleman atlanabilirdi.</p>

<h2 id="konteynerlere-göre-kurallar">Konteynerlere göre kurallar</h2>

<table>
  <thead>
    <tr>
      <th>Konteyner</th>
      <th>Silme sonrası genel iterator durumu</th>
      <th style="text-align: right">Silme maliyeti</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">vector</code></td>
      <td>Silinen ve sonrasındaki iterator’lar geçersiz</td>
      <td style="text-align: right">$O(n)$</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">deque</code></td>
      <td>Ortadan silmede çoğunlukla tüm iterator’lar geçersiz</td>
      <td style="text-align: right">$O(n)$</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">list</code>, <code class="language-plaintext highlighter-rouge">forward_list</code></td>
      <td>Yalnızca silinen elemana ait iterator geçersiz</td>
      <td style="text-align: right">$O(1)$</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">map</code>, <code class="language-plaintext highlighter-rouge">set</code></td>
      <td>Yalnızca silinen elemana ait iterator geçersiz</td>
      <td style="text-align: right">$O(\log n)$</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">unordered_map</code>, <code class="language-plaintext highlighter-rouge">unordered_set</code></td>
      <td>Genellikle yalnızca silinen elemana ait iterator geçersiz</td>
      <td style="text-align: right">Ortalama $O(1)$</td>
    </tr>
  </tbody>
</table>

<p><img src="/img/c-stlde-iterator-54.svg" alt="c-stlde-iterator-54" /></p>

<p><code class="language-plaintext highlighter-rouge">list</code> düğüm tabanlı olduğu için bir düğümün çıkarılması diğer düğümlerin adreslerini değiştirmez. <code class="language-plaintext highlighter-rouge">map</code> ve <code class="language-plaintext highlighter-rouge">set</code> gibi ağaç tabanlı yapılarda da benzer bir güvence vardır. Buna rağmen silinen iterator’ın kendisini kullanmak her durumda hatadır.</p>

<p><code class="language-plaintext highlighter-rouge">deque</code> daha dikkatli ele alınmalıdır: Baştan veya sondan silmenin kuralları daha sınırlı etkiler doğurabilirken ortadan silme, iterator’ları geniş ölçüde geçersizleştirir. Kodun taşınabilir ve anlaşılır olması için daima <code class="language-plaintext highlighter-rouge">erase</code> dönüş değerini kullanmak en güvenli yaklaşımdır.</p>

<h2 id="modern-c-ile-erase_if">Modern C++ ile erase_if</h2>

<p>Amaç yalnızca koşula uyan elemanları temizlemekse C++20, iterator yönetimini gizleyen daha okunaklı bir araç sunar:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;algorithm&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;vector&gt;</span><span class="cp">
</span>
<span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">sayilar</span><span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">};</span>

<span class="n">std</span><span class="o">::</span><span class="n">erase_if</span><span class="p">(</span><span class="n">sayilar</span><span class="p">,</span> <span class="p">[](</span><span class="kt">int</span> <span class="n">deger</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">deger</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">});</span>
</code></pre></div></div>

<p>Eski standartlarda <code class="language-plaintext highlighter-rouge">vector</code> için erase-remove deyimi kullanılır:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sayilar</span><span class="p">.</span><span class="n">erase</span><span class="p">(</span>
    <span class="n">std</span><span class="o">::</span><span class="n">remove_if</span><span class="p">(</span><span class="n">sayilar</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">sayilar</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span>
                   <span class="p">[](</span><span class="kt">int</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="n">x</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}),</span>
    <span class="n">sayilar</span><span class="p">.</span><span class="n">end</span><span class="p">()</span>
<span class="p">);</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">remove_if</code> fiziksel silme yapmaz; korunacak elemanları öne taşır ve mantıksal yeni sonu döndürür. Asıl küçültmeyi <code class="language-plaintext highlighter-rouge">erase</code> gerçekleştirir.</p>

<p>Kısa kural şudur: Bir silme işleminden sonra eski iterator’ın hâlâ geçerli olduğunu varsayma. Konteynerin geçersizleştirme kurallarını kontrol et, mümkünse <code class="language-plaintext highlighter-rouge">erase</code> tarafından döndürülen iterator’ı kullan ve toplu koşullu silmelerde <code class="language-plaintext highlighter-rouge">std::erase_if</code> tercih et. Böylece iterator’ların hayaletlere dönüşmesini engellersin.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="c++" /><category term="stl" /><category term="iterator" /><category term="konteynerler" /><category term="erase" /><category term="bellek" /><summary type="html"><![CDATA[Bir STL konteynerinde dolaşırken eleman silmek, ilk bakışta son derece masum görünür. Ancak yanlış kullanılan tek bir erase, yineleyiciyi geçersiz hâle getirerek tanımsız davranışa, atlanan elemanlara veya yalnızca cuma akşamları ortaya çıkan gizemli çökmelere neden olabilir. Bu tuzağın kaynağı, her konteynerin elemanlarını bellekte farklı biçimde saklamasıdır.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/c-stlde-iterator-54.png" /><media:content medium="image" url="https://program.sonsuz.us/img/c-stlde-iterator-54.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">grep, sed ve awk: Metin İşlerken Doğru Aleti Seçme Rehberi</title><link href="https://program.sonsuz.us/posts/grep-sed-ve-awk-metin-islerken-dogru-aleti-secme-rehberi/" rel="alternate" type="text/html" title="grep, sed ve awk: Metin İşlerken Doğru Aleti Seçme Rehberi" /><published>2026-10-20T00:00:00+00:00</published><updated>2026-10-20T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/grep-sed-ve-awk-metin-islerken-dogru-aleti-secme-rehberi</id><content type="html" xml:base="https://program.sonsuz.us/posts/grep-sed-ve-awk-metin-islerken-dogru-aleti-secme-rehberi/"><![CDATA[<p>Komut satırında her metin problemi bir çivi gibi görünüyorsa, elimizdeki ilk komutu çekiç olarak kullanmak cazip gelir. Böylece <code class="language-plaintext highlighter-rouge">grep</code> ile hesap yapmaya, <code class="language-plaintext highlighter-rouge">sed</code> ile sütun toplamaya veya <code class="language-plaintext highlighter-rouge">awk</code> ile yalnızca bir kelime aramaya çalışırız. Sonuç bazen çalışır; fakat okunabilirlik, taşınabilirlik ve bakım kolaylığı sessizce pencereden kaçar.</p>

<p><img src="/img/grep-sed-ve-18.svg" alt="grep-sed-ve-18" /></p>

<p>``</p>
<h2 id="üç-aracın-temel-zihinsel-modeli">Üç aracın temel zihinsel modeli</h2>

<p>Bu araçların hepsi standart girdiyi okuyabilir ve boru hatlarında kullanılabilir; ancak metne farklı gözlüklerle bakarlar.</p>

<ul>
  <li><strong>grep</strong>, satırların belirli bir desene uyup uymadığıyla ilgilenir.</li>
  <li><strong>sed</strong>, metni satır satır dönüştüren bir akış düzenleyicisidir.</li>
  <li><strong>awk</strong>, kayıtları alanlara ayırıp koşul, değişken ve aritmetik kullanabilen küçük bir programlama dilidir.</li>
</ul>

<p>Bir dosyada $n$ satır, her satırda ortalama $m$ karakter varsa basit tarama maliyeti kabaca $O(nm)$ olur. Araç seçiminin asıl farkı çoğunlukla teorik karmaşıklık değil, aynı işi ifade etmek için gereken zihinsel ve sözdizimsel karmaşıklıktır.</p>

<table>
  <thead>
    <tr>
      <th>Görev</th>
      <th>Doğru başlangıç aracı</th>
      <th>Temel güç</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Eşleşen satırları bulmak</td>
      <td><code class="language-plaintext highlighter-rouge">grep</code></td>
      <td>Düzenli ifadeyle filtreleme</td>
    </tr>
    <tr>
      <td>Metni değiştirmek veya silmek</td>
      <td><code class="language-plaintext highlighter-rouge">sed</code></td>
      <td>Akış üzerinde dönüşüm</td>
    </tr>
    <tr>
      <td>Sütunları işlemek ve hesaplamak</td>
      <td><code class="language-plaintext highlighter-rouge">awk</code></td>
      <td>Alanlar, koşullar ve aritmetik</td>
    </tr>
  </tbody>
</table>

<h2 id="grep-ile-tornavida-kullanmak">grep ile tornavida kullanmak</h2>

<p><code class="language-plaintext highlighter-rouge">grep</code> yalnızca eşleşen satırları seçmek için mükemmeldir:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">grep</span> <span class="nt">-i</span> <span class="s2">"error"</span> app.log
</code></pre></div></div>

<p>Bu komut, büyük-küçük harfi önemsemeden <code class="language-plaintext highlighter-rouge">error</code> içeren satırları getirir. Fakat ikinci sütundaki değerleri toplamak istiyorsak <code class="language-plaintext highlighter-rouge">grep</code>, görevi tek başına doğal biçimde ifade edemez. Karmaşık <code class="language-plaintext highlighter-rouge">grep</code>, <code class="language-plaintext highlighter-rouge">cut</code>, <code class="language-plaintext highlighter-rouge">paste</code> ve <code class="language-plaintext highlighter-rouge">bc</code> zincirleri kurulabilir; ancak bu, market alışverişine forkliftle gitmeye benzer.</p>

<p>Doğal çözüm <code class="language-plaintext highlighter-rouge">awk</code> kullanmaktır:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">awk</span> <span class="s1">'{ toplam += $2 } END { print toplam }'</span> satis.txt
</code></pre></div></div>

<p>Burada her satır bir kayıt, boşluklarla ayrılmış parçalar ise alan kabul edilir. <code class="language-plaintext highlighter-rouge">$2</code> ikinci alanı, <code class="language-plaintext highlighter-rouge">END</code> ise bütün kayıtlar işlendikten sonraki aşamayı temsil eder.</p>

<h2 id="sed-ile-muhasebe-yapmaya-çalışmak">sed ile muhasebe yapmaya çalışmak</h2>

<p><code class="language-plaintext highlighter-rouge">sed</code>, değiştirme işlemlerinde parlar:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sed</span> <span class="s1">'s/http:/https:/g'</span> adresler.txt
</code></pre></div></div>

<p>Komut, her satırdaki tüm <code class="language-plaintext highlighter-rouge">http:</code> ifadelerini <code class="language-plaintext highlighter-rouge">https:</code> ile değiştirir. Buna karşılık sayısal karşılaştırma, toplam veya ortalama gerektiğinde <code class="language-plaintext highlighter-rouge">sed</code> komutları hızla anlaşılmaz hâle gelir.</p>

<p>Örneğin üçüncü sütunu 100’den büyük kayıtları seçmek için doğru yaklaşım şudur:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">awk</span> <span class="s1">'$3 &gt; 100 { print $1, $3 }'</span> veriler.txt
</code></pre></div></div>

<p>Ortalama hesaplamak da doğrudandır. Değerlerin toplamı $S$, kayıt sayısı $N$ ise ortalama</p>

\[\bar{x} = \frac{S}{N}\]

<p>olur:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">awk</span> <span class="s1">'{ s += $3; n++ } END { if (n) print s / n }'</span> veriler.txt
</code></pre></div></div>

<h2 id="awk-ile-basit-aramayı-büyütmek">awk ile basit aramayı büyütmek</h2>

<p><code class="language-plaintext highlighter-rouge">awk '/hata/' app.log</code> geçerli bir komuttur; fakat yalnızca eşleşen satırları istiyorsak niyetimizi <code class="language-plaintext highlighter-rouge">grep 'hata' app.log</code> daha açık anlatır. <code class="language-plaintext highlighter-rouge">awk</code>, alan seçimi veya ek mantık devreye girdiğinde anlam kazanır:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">awk</span> <span class="s1">'$2 == "ERROR" &amp;&amp; $4 &gt;= 500 { print $1, $4 }'</span> app.log
</code></pre></div></div>

<p>Bu örnek hem alan karşılaştırır hem sayısal koşul uygular. Yani <code class="language-plaintext highlighter-rouge">awk</code> burada gerçekten maaşını hak eder.</p>

<h2 id="araçlar-rakip-değil-ekip-arkadaşıdır">Araçlar rakip değil, ekip arkadaşıdır</h2>

<p>Tek bir komuta bütün işi yüklemek zorunda değiliz. Önce ilgili satırları filtreleyip sonra metni dönüştürebiliriz:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">grep</span> <span class="s1">'^WARN'</span> app.log | <span class="nb">sed</span> <span class="s1">'s/^WARN/UYARI/'</span>
</code></pre></div></div>

<p>Yine de gereksiz süreçlerden kaçınmak gerekir. Aynı işlem tek ve anlaşılır bir <code class="language-plaintext highlighter-rouge">awk</code> programıyla yapılabiliyorsa uzun boru hattı kurmak hata ayıklamayı zorlaştırabilir.</p>

<p>Pratik karar kuralı basittir: <strong>Buluyorsan grep, değiştiriyorsan sed, alanlar üzerinde düşünüyor veya hesaplıyorsan awk.</strong> Görev büyüdükçe kabuk komutlarını zorlamak yerine Python gibi genel amaçlı bir dile geçmek de yenilgi değil, doğru mühendislik kararıdır.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="shell" /><category term="grep" /><category term="sed" /><category term="awk" /><category term="linux" /><category term="metin işleme" /><summary type="html"><![CDATA[Komut satırında her metin problemi bir çivi gibi görünüyorsa, elimizdeki ilk komutu çekiç olarak kullanmak cazip gelir. Böylece grep ile hesap yapmaya, sed ile sütun toplamaya veya awk ile yalnızca bir kelime aramaya çalışırız. Sonuç bazen çalışır; fakat okunabilirlik, taşınabilirlik ve bakım kolaylığı sessizce pencereden kaçar.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/grep-sed-ve-18.png" /><media:content medium="image" url="https://program.sonsuz.us/img/grep-sed-ve-18.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Robotlarda Holonomik ve Non-Holonomik Kısıtlar: Yol Planlamanın Görünmez Kuralları</title><link href="https://program.sonsuz.us/posts/robotlarda-holonomik-ve-non-holonomik-kisitlar-yol-planlamanin-gorunmez-kurallari/" rel="alternate" type="text/html" title="Robotlarda Holonomik ve Non-Holonomik Kısıtlar: Yol Planlamanın Görünmez Kuralları" /><published>2026-10-20T00:00:00+00:00</published><updated>2026-10-20T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/robotlarda-holonomik-ve-non-holonomik-kisitlar-yol-planlamanin-gorunmez-kurallari</id><content type="html" xml:base="https://program.sonsuz.us/posts/robotlarda-holonomik-ve-non-holonomik-kisitlar-yol-planlamanin-gorunmez-kurallari/"><![CDATA[<p>Bir robotun harita üzerinde boş bir nokta bulması, o noktaya gerçekten ulaşabileceği anlamına gelmez. Satranç taşları gibi robotların da hareket kuralları vardır: Holonomik robotlar yana kayabilirken non-holonomik robotlar çoğunlukla önce yönelmek, sonra ilerlemek zorundadır. Yol planlayıcı bu fiziksel gerçeği hesaba katmazsa kusursuz görünen rota, gerçek dünyada duvara sürtünen pahalı bir hayale dönüşebilir.</p>

<p>``</p>

<h2 id="hareket-kısıtı-ne-demektir">Hareket kısıtı ne demektir?</h2>

<p>Bir robotun konfigürasyonu genellikle</p>

\[q = (x, y, \theta)\]

<p>ile gösterilir. Burada $x$ ve $y$ konumu, $\theta$ ise yönelimi temsil eder. Robot üç boyutlu bir konfigürasyon uzayında bulunsa da her yönde anlık hız üretemeyebilir.</p>

<p>Bir kısıt yalnızca konfigürasyon değişkenleriyle</p>

\[f(q)=0\]

<p>şeklinde yazılabiliyorsa <strong>holonomik</strong> kabul edilir. Kısıt hızlara bağlıysa ve konum düzeyinde bütünleştirilemiyorsa non-holonomik davranış ortaya çıkar. Bu tür kısıtların yaygın gösterimi şöyledir:</p>

\[A(q)\dot{q}=0\]

<p>Örneğin diferansiyel sürüşlü bir robotun yana kaymama koşulu:</p>

\[-\sin(\theta)\dot{x}+\cos(\theta)\dot{y}=0\]

<p>biçimindedir. Denklem basitçe şunu söyler: Robotun tekerlek ekseni doğrultusunda yanal hızı yoktur. Yani robot araba park eder gibi birkaç manevra yapmak zorunda kalabilir.</p>

<h2 id="i̇ki-hareket-dünyasının-karşılaştırması">İki hareket dünyasının karşılaştırması</h2>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>Holonomik robot</th>
      <th>Non-holonomik robot</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Anlık hareket</td>
      <td>Serbestlik derecelerinde bağımsız</td>
      <td>Belirli hız yönleriyle sınırlı</td>
    </tr>
    <tr>
      <td>Tipik örnek</td>
      <td>Omni veya mecanum tekerlekli platform</td>
      <td>Otomobil, bisiklet, diferansiyel robot</td>
    </tr>
    <tr>
      <td>Yana hareket</td>
      <td>Genellikle mümkün</td>
      <td>Doğrudan mümkün değil</td>
    </tr>
    <tr>
      <td>Planlama uzayı</td>
      <td>Çoğu zaman $(x,y)$ yeterli olabilir</td>
      <td>$(x,y,\theta)$ gerekir</td>
    </tr>
    <tr>
      <td>Rota biçimi</td>
      <td>Keskin dönüşler mümkün</td>
      <td>Eğrilik ve dönüş yarıçapı önemlidir</td>
    </tr>
    <tr>
      <td>Planlama maliyeti</td>
      <td>Görece düşük</td>
      <td>Daha yüksek</td>
    </tr>
  </tbody>
</table>

<p><img src="/img/robotlarda-holonomik-ve-78.svg" alt="robotlarda-holonomik-ve-78" /></p>

<p>Holonomik bir platform için A* algoritması iki boyutlu ızgarada kısa bir yol bulabilir. Robot, gerektiğinde yönünü değiştirmeden yana kayabilir. Non-holonomik bir araçta ise aynı yol üzerindeki doksan derecelik köşe fiziksel olarak uygulanamayabilir.</p>

<h2 id="yol-planlamasına-etkisi">Yol planlamasına etkisi</h2>

<p>Non-holonomik planlamada yalnızca engellerden kaçmak yetmez. Planlayıcı; yönelim, minimum dönüş yarıçapı, geri hareket izni ve direksiyon sınırı gibi değişkenleri de değerlendirmelidir. Bu nedenle klasik A* yerine <strong>Hybrid A</strong>*, <strong>state lattice</strong>, <strong>RRT</strong>, <strong>RRT*</strong> veya Dubins ve Reeds–Shepp eğrileri kullanılabilir.</p>

<p>Dubins aracı yalnızca ileri hareket eder ve eğriliği sınırlıdır. Reeds–Shepp modeli ise geri vitese de izin verir. Böylece iki durum arasındaki mesafe, Öklid uzaklığından daha gerçekçi hesaplanır:</p>

\[d_{gerçek}(q_1,q_2) \geq d_{Öklid}(q_1,q_2)\]

<p>Çünkü kuş uçuşu en kısa çizgi, otomobil sürüşü açısından her zaman uygulanabilir değildir.</p>

<h2 id="basit-bir-kısıt-kontrolü">Basit bir kısıt kontrolü</h2>

<p>Aşağıdaki Python fonksiyonu, diferansiyel robotun verilen dünya hızlarında yanal kayma üretip üretmediğini denetler:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">math</span>

<span class="k">def</span> <span class="nf">hareket_gecerli_mi</span><span class="p">(</span><span class="n">theta</span><span class="p">,</span> <span class="n">vx</span><span class="p">,</span> <span class="n">vy</span><span class="p">,</span> <span class="n">tolerans</span><span class="o">=</span><span class="mf">1e-3</span><span class="p">):</span>
    <span class="c1"># Robot gövdesine göre yanal hız bileşenini hesaplar.
</span>    <span class="n">yanal_hiz</span> <span class="o">=</span> <span class="o">-</span><span class="n">math</span><span class="p">.</span><span class="nf">sin</span><span class="p">(</span><span class="n">theta</span><span class="p">)</span> <span class="o">*</span> <span class="n">vx</span> <span class="o">+</span> <span class="n">math</span><span class="p">.</span><span class="nf">cos</span><span class="p">(</span><span class="n">theta</span><span class="p">)</span> <span class="o">*</span> <span class="n">vy</span>
    <span class="k">return</span> <span class="nf">abs</span><span class="p">(</span><span class="n">yanal_hiz</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">tolerans</span>

<span class="nf">print</span><span class="p">(</span><span class="nf">hareket_gecerli_mi</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">))</span>  <span class="c1"># True: ileri hareket
</span><span class="nf">print</span><span class="p">(</span><span class="nf">hareket_gecerli_mi</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">))</span>  <span class="c1"># False: doğrudan yana kayma
</span></code></pre></div></div>

<p>Gerçek bir planlayıcı, komşu durum üretirken yalnızca bu koşulu test etmekle kalmaz; robotun hareket modelini kısa bir süre boyunca simüle eder. Örneğin</p>

\[\dot{x}=v\cos\theta,\qquad \dot{y}=v\sin\theta,\qquad \dot{\theta}=\omega\]

<p>modeliyle farklı $v$ ve $\omega$ komutları denenerek erişilebilir yeni düğümler oluşturulur. Böylece arama ağacındaki her bağlantı gerçekten uygulanabilir olur.</p>

<h2 id="sonuç">Sonuç</h2>

<p>Holonomik planlama geometrik olarak “Nereden geçebilirim?” sorusuna odaklanırken non-holonomik planlama buna “Oraya hangi yönelim ve manevrayla ulaşabilirim?” sorusunu ekler. Daha gerçekçi kısıtlar daha fazla hesaplama gerektirir; ancak uygulanamayan kısa bir yol yerine güvenli, pürüzsüz ve sürülebilir bir rota üretir. Robotik dünyasında en kısa yol bazen düz çizgi değil, doğru kıvrımdır.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="robotik" /><category term="yol planlama" /><category term="holonomik" /><category term="non-holonomik" /><category term="kinematik" /><category term="otonom robotlar" /><summary type="html"><![CDATA[Bir robotun harita üzerinde boş bir nokta bulması, o noktaya gerçekten ulaşabileceği anlamına gelmez. Satranç taşları gibi robotların da hareket kuralları vardır: Holonomik robotlar yana kayabilirken non-holonomik robotlar çoğunlukla önce yönelmek, sonra ilerlemek zorundadır. Yol planlayıcı bu fiziksel gerçeği hesaba katmazsa kusursuz görünen rota, gerçek dünyada duvara sürtünen pahalı bir hayale dönüşebilir.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/robotlarda-holonomik-ve-78.png" /><media:content medium="image" url="https://program.sonsuz.us/img/robotlarda-holonomik-ve-78.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Shell Betiklerinde Sürpriz Ünlem: History Expansion Tuzağı</title><link href="https://program.sonsuz.us/posts/shell-betiklerinde-surpriz-unlem-history-expansion-tuzagi/" rel="alternate" type="text/html" title="Shell Betiklerinde Sürpriz Ünlem: History Expansion Tuzağı" /><published>2026-10-20T00:00:00+00:00</published><updated>2026-10-20T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/shell-betiklerinde-surpriz-unlem-history-expansion-tuzagi</id><content type="html" xml:base="https://program.sonsuz.us/posts/shell-betiklerinde-surpriz-unlem-history-expansion-tuzagi/"><![CDATA[<p>Bir betik çalıştırıyorsunuz; parola, URL veya mesaj içinde sıradan bir <code class="language-plaintext highlighter-rouge">!</code> karakteri var. Birden terminal <code class="language-plaintext highlighter-rouge">event not found</code> diye bağırıyor ya da komutunuz beklenmedik biçimde değişiyor. Suçlu çoğu zaman Bash’in <strong>history expansion</strong> özelliğidir. Ünlem işareti kabuk için yalnızca heyecan belirtmez; geçmiş komutlara açılan gizli bir kapı da olabilir.</p>

<p><img src="/img/shell-betiklerinde-surpriz-33.svg" alt="shell-betiklerinde-surpriz-33" /></p>

<p>``</p>

<h2 id="history-expansion-nedir">History expansion nedir?</h2>

<p>Bash, etkileşimli kullanımda önceki komutları hızlıca çağırmak için <code class="language-plaintext highlighter-rouge">!</code> ile başlayan ifadeleri yorumlayabilir. Örneğin <code class="language-plaintext highlighter-rouge">!!</code> son komutu, <code class="language-plaintext highlighter-rouge">!42</code> geçmişteki 42 numaralı komutu, <code class="language-plaintext highlighter-rouge">!git</code> ise <code class="language-plaintext highlighter-rouge">git</code> ile başlayan son komutu temsil eder.</p>

<p>Bunu basitçe şu dönüşümle düşünebiliriz:</p>

\[\text{çalıştırılan komut} = H(\text{yazılan metin})\]

<p>Buradaki $H$, history expansion etkinse ünlem ifadelerini geçmişteki komutlarla değiştiren fonksiyondur. Özellik kapalıysa $H(x)=x$ olur; yani metin değişmeden kalır.</p>

<table>
  <thead>
    <tr>
      <th>Yazılan ifade</th>
      <th>Özellik açıkken olası anlamı</th>
      <th>Özellik kapalıyken</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">!!</code></td>
      <td>Son komut</td>
      <td>İki ünlem karakteri</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">!42</code></td>
      <td>42 numaralı geçmiş girdisi</td>
      <td>Değişmeden kalır</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">!echo</code></td>
      <td>Son <code class="language-plaintext highlighter-rouge">echo</code> komutu</td>
      <td>Değişmeden kalır</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">merhaba!</code></td>
      <td>Genellikle aynı kalır</td>
      <td>Aynı kalır</td>
    </tr>
  </tbody>
</table>

<p>Bash’in <strong>etkileşimli olmayan</strong> betiklerinde history expansion normalde kapalıdır. Ancak betik <code class="language-plaintext highlighter-rouge">source</code> ile etkileşimli bir kabuğa yüklenirse, <code class="language-plaintext highlighter-rouge">bash -H</code> ile başlatılırsa veya kod içinde <code class="language-plaintext highlighter-rouge">set -H</code> çalıştırılırsa özellik devreye girebilir. Bu yüzden “Betikte asla olmaz” varsayımı güvenli değildir.</p>

<h2 id="çifte-tırnak-her-zaman-korumaz">Çifte tırnak her zaman korumaz</h2>

<p>Shell programlamasında çifte tırnağın özel karakterleri tamamen etkisizleştirdiği sanılır. Oysa history expansion etkin olduğunda <code class="language-plaintext highlighter-rouge">!</code>, çifte tırnak içinde de yorumlanabilir:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/usr/bin/env bash</span>
<span class="nb">set</span> <span class="nt">-H</span>

<span class="nv">password</span><span class="o">=</span><span class="s2">"Guclu!Parola"</span>
<span class="nb">echo</span> <span class="s2">"</span><span class="nv">$password</span><span class="s2">"</span>
</code></pre></div></div>

<p>Bash, <code class="language-plaintext highlighter-rouge">!Parola</code> için uygun bir geçmiş olayı arayabilir ve <code class="language-plaintext highlighter-rouge">event not found</code> hatası üretebilir. Üstelik expansion, değişkenin değerinden çok kaynak satırı okunurken önem kazanır. Bu nedenle davranış kabuk sürümüne, çalışma biçimine ve bağlama göre şaşırtıcı görünebilir.</p>

<h2 id="en-güvenli-çözüm-özelliği-kapatmak">En güvenli çözüm: Özelliği kapatmak</h2>

<p>History expansion gerekmeyen bir betiğin başında özelliği açıkça kapatabilirsiniz:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/usr/bin/env bash</span>
<span class="nb">set</span> +H
<span class="c"># Aynı işlemin daha açıklayıcı karşılığı:</span>
<span class="nb">set</span> +o histexpand

<span class="nv">message</span><span class="o">=</span><span class="s2">"Dağıtım tamamlandı!"</span>
<span class="nb">printf</span> <span class="s1">'%s\n'</span> <span class="s2">"</span><span class="nv">$message</span><span class="s2">"</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">set +H</code>, <code class="language-plaintext highlighter-rouge">histexpand</code> seçeneğini kapatır. Buradaki artı işaretinin seçeneği kapatması ilk bakışta ters gelebilir: Bash’te <code class="language-plaintext highlighter-rouge">set -H</code> açar, <code class="language-plaintext highlighter-rouge">set +H</code> kapatır.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th style="text-align: right">Güvenilirlik</th>
      <th>Kullanım amacı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">set +H</code></td>
      <td style="text-align: right">Yüksek</td>
      <td>Betik genelinde expansion’ı kapatır</td>
    </tr>
    <tr>
      <td>Tek tırnak kullanmak</td>
      <td style="text-align: right">Yüksek</td>
      <td>Sabit metni korur</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">\!</code> ile kaçırmak</td>
      <td style="text-align: right">Orta</td>
      <td>Belirli bir ünlemi korur</td>
    </tr>
    <tr>
      <td>Çifte tırnağa güvenmek</td>
      <td style="text-align: right">Düşük</td>
      <td>History expansion için yeterli olmayabilir</td>
    </tr>
  </tbody>
</table>

<p>Sabit bir değer söz konusuysa tek tırnak da kullanılabilir:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">printf</span> <span class="s1">'%s\n'</span> <span class="s1">'İşlem başarılı!'</span>
<span class="nb">printf</span> <span class="s1">'%s\n'</span> <span class="s1">'api-token: abc!123'</span>
</code></pre></div></div>

<p>Ancak tek tırnak içinde değişken genişletmesi yapılmaz. Örneğin <code class="language-plaintext highlighter-rouge">'Merhaba $USER!'</code>, kullanıcı adını değil, doğrudan <code class="language-plaintext highlighter-rouge">$USER</code> metnini yazdırır.</p>

<h2 id="durumu-teşhis-etmek">Durumu teşhis etmek</h2>

<p>Seçeneğin mevcut durumunu aşağıdaki komutla görebilirsiniz:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">set</span> <span class="nt">-o</span> | <span class="nb">grep </span>histexpand
</code></pre></div></div>

<p>Çıktıda <code class="language-plaintext highlighter-rouge">histexpand on</code> görülüyorsa ünlem genişletmesi açıktır. Betik <code class="language-plaintext highlighter-rouge">source script.sh</code> biçiminde çalıştırılıyorsa aynı kabuğun seçeneklerini miras alabileceğini unutmayın. Bağımsız çalıştırma için yürütme izni verip <code class="language-plaintext highlighter-rouge">./script.sh</code> kullanmak daha öngörülebilir olabilir.</p>

<p>Özetle ünlem kaynaklı hatalarda yalnızca kaçış karakterleriyle boğuşmayın. Önce kabuğun türünü, betiğin nasıl çalıştırıldığını ve <code class="language-plaintext highlighter-rouge">histexpand</code> durumunu kontrol edin. Otomasyon kodunda geçmiş komut sihrine ihtiyaç yoksa <code class="language-plaintext highlighter-rouge">set +H</code> diyerek sürprizi daha perde açılmadan bitirin.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="shell" /><category term="bash" /><category term="history-expansion" /><category term="betik" /><category term="linux" /><category term="hata-ayiklama" /><summary type="html"><![CDATA[Bir betik çalıştırıyorsunuz; parola, URL veya mesaj içinde sıradan bir ! karakteri var. Birden terminal event not found diye bağırıyor ya da komutunuz beklenmedik biçimde değişiyor. Suçlu çoğu zaman Bash’in history expansion özelliğidir. Ünlem işareti kabuk için yalnızca heyecan belirtmez; geçmiş komutlara açılan gizli bir kapı da olabilir.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/shell-betiklerinde-surpriz-33.png" /><media:content medium="image" url="https://program.sonsuz.us/img/shell-betiklerinde-surpriz-33.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">C Göstericiler: Belleğin Adres Defterini Okumak</title><link href="https://program.sonsuz.us/posts/c-gostericiler-bellegin-adres-defterini-okumak/" rel="alternate" type="text/html" title="C Göstericiler: Belleğin Adres Defterini Okumak" /><published>2026-10-19T00:00:00+00:00</published><updated>2026-10-19T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/c-gostericiler-bellegin-adres-defterini-okumak</id><content type="html" xml:base="https://program.sonsuz.us/posts/c-gostericiler-bellegin-adres-defterini-okumak/"><![CDATA[<p>C dilinde göstericiler, ilk karşılaşmada belleğin karanlık sokaklarında dolaşmak gibi görünebilir. Oysa bir gösterici yalnızca başka bir nesnenin bellekteki adresini saklayan değişkendir. Bu mekanizmayı kavradığınızda dizilerin, dinamik belleğin, fonksiyon parametrelerinin ve veri yapılarının neden bu kadar verimli çalıştığını da anlamaya başlarsınız.</p>

<p>``</p>

<h2 id="değer-değil-adres-saklamak">Değer Değil, Adres Saklamak</h2>

<p>Normal bir değişken doğrudan veri taşır. Gösterici ise bu verinin bulunduğu konumu taşır. Örneğin <code class="language-plaintext highlighter-rouge">int sayi = 42;</code> ifadesi bellekte bir tamsayı oluşturur. <code class="language-plaintext highlighter-rouge">&amp;sayi</code>, bu değişkenin adresini verir; <code class="language-plaintext highlighter-rouge">*ptr</code> ise göstericinin tuttuğu adrese giderek oradaki değere erişir.</p>

<table>
  <thead>
    <tr>
      <th>İfade</th>
      <th>Anlamı</th>
      <th>Örnek sonuç</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">sayi</code></td>
      <td>Değişkenin değeri</td>
      <td><code class="language-plaintext highlighter-rouge">42</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">&amp;sayi</code></td>
      <td>Değişkenin adresi</td>
      <td><code class="language-plaintext highlighter-rouge">0x7ffd...</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">ptr</code></td>
      <td>Göstericide saklanan adres</td>
      <td><code class="language-plaintext highlighter-rouge">0x7ffd...</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">*ptr</code></td>
      <td>Adresteki değer</td>
      <td><code class="language-plaintext highlighter-rouge">42</code></td>
    </tr>
  </tbody>
</table>

<p><img src="/img/c-gostericiler-bellegin-75.svg" alt="c-gostericiler-bellegin-75" /></p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">sayi</span> <span class="o">=</span> <span class="mi">42</span><span class="p">;</span>
    <span class="kt">int</span> <span class="o">*</span><span class="n">ptr</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">sayi</span><span class="p">;</span>

    <span class="n">printf</span><span class="p">(</span><span class="s">"Deger: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">sayi</span><span class="p">);</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"Adres: %p</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="n">ptr</span><span class="p">);</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"Pointer uzerinden deger: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="o">*</span><span class="n">ptr</span><span class="p">);</span>

    <span class="o">*</span><span class="n">ptr</span> <span class="o">=</span> <span class="mi">99</span><span class="p">;</span> <span class="cm">/* Adresteki gerçek değeri değiştirir. */</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"Yeni deger: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">sayi</span><span class="p">);</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">int *ptr</code>, <code class="language-plaintext highlighter-rouge">ptr</code> değişkeninin bir <code class="language-plaintext highlighter-rouge">int</code> adresi taşıyacağını belirtir. <code class="language-plaintext highlighter-rouge">*ptr = 99</code> işlemi kopyayı değil, doğrudan <code class="language-plaintext highlighter-rouge">sayi</code> değişkenini değiştirir. Göstericilerin fonksiyonlara “dışarıdaki” veriyi değiştirme gücü vermesi de bu mantığa dayanır.</p>

<h2 id="bellek-ve-tür-bilgisi">Bellek ve Tür Bilgisi</h2>

<p>Bir adresi yalnızca sayı gibi düşünmek eksik kalır. Göstericinin türü, derleyiciye o adreste kaç baytlık ve nasıl yorumlanacak bir veri bulunduğunu söyler. Tipik bir sistemde <code class="language-plaintext highlighter-rouge">char</code> 1 bayt, <code class="language-plaintext highlighter-rouge">int</code> 4 bayt olabilir; ancak kesin boyutlar platforma bağlıdır ve <code class="language-plaintext highlighter-rouge">sizeof</code> ile öğrenilmelidir.</p>

<p>Bir dizinin başlangıç adresi $A$, eleman boyutu $s$ ve erişilecek indis $i$ olsun. İlgili elemanın adresi şu şekilde hesaplanır:</p>

\[\operatorname{adres}(dizi[i]) = A + i \times s\]

<p>Bu nedenle işaretçi aritmetiği sıradan tam sayı aritmetiğinden farklıdır. <code class="language-plaintext highlighter-rouge">ptr + 1</code>, adresi bir bayt değil, gösterilen türün boyutu kadar ilerletir.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">sayilar</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">30</span><span class="p">,</span> <span class="mi">40</span><span class="p">};</span>
    <span class="kt">int</span> <span class="o">*</span><span class="n">ptr</span> <span class="o">=</span> <span class="n">sayilar</span><span class="p">;</span>

    <span class="k">for</span> <span class="p">(</span><span class="kt">size_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">4</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"%zu: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="o">*</span><span class="p">(</span><span class="n">ptr</span> <span class="o">+</span> <span class="n">i</span><span class="p">));</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">*(ptr + i)</code> ile <code class="language-plaintext highlighter-rouge">ptr[i]</code> eşdeğerdir. Hatta <code class="language-plaintext highlighter-rouge">sayilar[i]</code> ifadesi de temelde başlangıç adresinden uygun miktarda ilerleyip değeri çözme işlemidir.</p>

<table>
  <thead>
    <tr>
      <th>İşlem</th>
      <th>Etki</th>
      <th>Güvenli kullanım</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">ptr++</code></td>
      <td>Sonraki elemana geçer</td>
      <td>Dizi sınırları içinde</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">ptr--</code></td>
      <td>Önceki elemana geçer</td>
      <td>Başlangıcın gerisine gitmeden</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">ptr2 - ptr1</code></td>
      <td>Eleman uzaklığını verir</td>
      <td>Aynı dizi üzerinde</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">ptr + i</code></td>
      <td><code class="language-plaintext highlighter-rouge">i</code> eleman ilerler</td>
      <td>Geçerli aralıkta</td>
    </tr>
  </tbody>
</table>

<h2 id="null-ve-tehlikeli-göstericiler">NULL ve Tehlikeli Göstericiler</h2>

<p>Başlatılmamış bir gösterici rastgele bir adres taşıyabilir. <code class="language-plaintext highlighter-rouge">NULL</code>, göstericinin geçerli bir nesneyi göstermediğini açıkça belirtir. Ancak <code class="language-plaintext highlighter-rouge">NULL</code> göstericiyi çözmek, yani <code class="language-plaintext highlighter-rouge">*ptr</code> kullanmak tanımsız davranıştır.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="o">*</span><span class="n">ptr</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>

<span class="k">if</span> <span class="p">(</span><span class="n">ptr</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
    <span class="cm">/* Yalnızca geçerli adres varsa erişilir. */</span>
    <span class="o">*</span><span class="n">ptr</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Benzer şekilde yaşam süresi bitmiş yerel değişkenlerin adresleri ve <code class="language-plaintext highlighter-rouge">free</code> ile serbest bırakılmış bölgeleri gösteren işaretçiler “sarkan gösterici” oluşturur. Dizi sınırını aşmak da komşunun posta kutusunu kendi kutunuz sanmaya benzer: Adres vardır, fakat erişim hakkınız yoktur.</p>

<h2 id="sonuç">Sonuç</h2>

<p>Göstericiler C’nin performans ve kontrol gücünün merkezindedir. <code class="language-plaintext highlighter-rouge">&amp;</code> adres alır, <code class="language-plaintext highlighter-rouge">*</code> adresteki veriyi çözer, tür bilgisi ise aritmetik adımların boyutunu belirler. Güvenli kullanım için göstericileri başlatmak, <code class="language-plaintext highlighter-rouge">NULL</code> kontrolü yapmak, nesnelerin yaşam süresini izlemek ve dizi sınırlarını korumak gerekir. Bu kurallar oturduğunda belleğin karanlık sokakları, tabelaları gayet okunaklı bir mahalleye dönüşür.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="c" /><category term="göstericiler" /><category term="bellek" /><category term="pointer" /><category term="işaretçi-aritmetiği" /><category term="programlama" /><summary type="html"><![CDATA[C dilinde göstericiler, ilk karşılaşmada belleğin karanlık sokaklarında dolaşmak gibi görünebilir. Oysa bir gösterici yalnızca başka bir nesnenin bellekteki adresini saklayan değişkendir. Bu mekanizmayı kavradığınızda dizilerin, dinamik belleğin, fonksiyon parametrelerinin ve veri yapılarının neden bu kadar verimli çalıştığını da anlamaya başlarsınız.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/c-gostericiler-bellegin-75.png" /><media:content medium="image" url="https://program.sonsuz.us/img/c-gostericiler-bellegin-75.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">C Önişlemci Komutları: Makrolar ve Koşullu Derleme Rehberi</title><link href="https://program.sonsuz.us/posts/c-onislemci-komutlari-makrolar-ve-kosullu-derleme-rehberi/" rel="alternate" type="text/html" title="C Önişlemci Komutları: Makrolar ve Koşullu Derleme Rehberi" /><published>2026-10-19T00:00:00+00:00</published><updated>2026-10-19T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/c-onislemci-komutlari-makrolar-ve-kosullu-derleme-rehberi</id><content type="html" xml:base="https://program.sonsuz.us/posts/c-onislemci-komutlari-makrolar-ve-kosullu-derleme-rehberi/"><![CDATA[<p>C dilinde kaynak kod, doğrudan makine koduna çevrilmez; önce birkaç aşamadan geçen küçük bir yolculuğa çıkar. Önişlemci, bu yolculuğun derlemeden hemen önceki durağıdır. <code class="language-plaintext highlighter-rouge">#include</code>, <code class="language-plaintext highlighter-rouge">#define</code> ve <code class="language-plaintext highlighter-rouge">#if</code> gibi direktifleri işler; başlık dosyalarını ekler, makroları genişletir ve hangi kod parçalarının derleyiciye ulaşacağını belirler. Kısacası önişlemci, sahne açılmadan önce dekoru hazırlayan görünmez bir ekip gibidir.
``</p>

<h2 id="derlemeden-önce-neler-olur">Derlemeden önce neler olur?</h2>

<p>Tipik bir C programının üretim süreci kabaca dört aşamaya ayrılır:</p>

<table>
  <thead>
    <tr>
      <th>Aşama</th>
      <th>Girdi</th>
      <th>Yapılan işlem</th>
      <th>Çıktı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Önişleme</td>
      <td><code class="language-plaintext highlighter-rouge">.c</code> dosyası</td>
      <td>Direktifler ve makrolar işlenir</td>
      <td>Genişletilmiş kaynak kod</td>
    </tr>
    <tr>
      <td>Derleme</td>
      <td>Genişletilmiş kod</td>
      <td>C kodu assembly diline çevrilir</td>
      <td>Assembly kodu</td>
    </tr>
    <tr>
      <td>Assembly</td>
      <td>Assembly kodu</td>
      <td>Makine komutları oluşturulur</td>
      <td>Nesne dosyası</td>
    </tr>
    <tr>
      <td>Bağlama</td>
      <td>Nesne dosyaları</td>
      <td>Kütüphaneler birleştirilir</td>
      <td>Çalıştırılabilir program</td>
    </tr>
  </tbody>
</table>

<p>Bu süreci sembolik olarak şöyle gösterebiliriz:</p>

\[Kaynak \rightarrow Önişlemci \rightarrow Derleyici \rightarrow Assembler \rightarrow Bağlayıcı\]

<p>GCC kullanırken yalnızca önişlemci çıktısını görmek için şu komut çalıştırılabilir:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc <span class="nt">-E</span> program.c <span class="nt">-o</span> program.i
</code></pre></div></div>

<p>Oluşan <code class="language-plaintext highlighter-rouge">program.i</code> dosyası genellikle oldukça uzundur; çünkü eklenen başlıkların içeriği de bu dosyada görünür.</p>

<h2 id="include-başlık-dosyalarını-eklemek"><code class="language-plaintext highlighter-rouge">#include</code>: Başlık dosyalarını eklemek</h2>

<p><code class="language-plaintext highlighter-rouge">#include</code>, belirtilen dosyanın içeriğini mevcut kaynak dosyaya metinsel olarak ekler:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">"hesaplama.h"</span><span class="cp">
</span></code></pre></div></div>

<table>
  <thead>
    <tr>
      <th>Yazım</th>
      <th>Genel kullanım</th>
      <th>Arama davranışı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">&lt;stdio.h&gt;</code></td>
      <td>Standart veya sistem başlıkları</td>
      <td>Sistem başlık dizinleri aranır</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">"hesaplama.h"</code></td>
      <td>Projeye ait başlıklar</td>
      <td>Önce mevcut proje dizini aranır</td>
    </tr>
  </tbody>
</table>

<p>Aynı başlığın birden fazla kez eklenmesi tanım çakışmalarına yol açabilir. Bu nedenle include guard kullanılır:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#ifndef HESAPLAMA_H
#define HESAPLAMA_H
</span>
<span class="kt">int</span> <span class="nf">topla</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">);</span>

<span class="cp">#endif
</span></code></pre></div></div>

<p>İlk eklemede <code class="language-plaintext highlighter-rouge">HESAPLAMA_H</code> tanımlanır. Sonraki eklemelerde <code class="language-plaintext highlighter-rouge">#ifndef</code> koşulu yanlış olacağı için dosyanın gövdesi atlanır.</p>

<h2 id="define-metinsel-dönüşüm-yapan-makrolar"><code class="language-plaintext highlighter-rouge">#define</code>: Metinsel dönüşüm yapan makrolar</h2>

<p>Nesne benzeri makrolar sabit değerleri temsil edebilir:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define PI 3.141592653589793
#define MAKSIMUM_KULLANICI 100
</span></code></pre></div></div>

<p>Örneğin dairenin alanı $A = \pi r^2$ bağıntısıyla hesaplanabilir:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define PI 3.141592653589793
#define KARE(x) ((x) * (x))
</span>
<span class="kt">double</span> <span class="nf">alan</span><span class="p">(</span><span class="kt">double</span> <span class="n">yaricap</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">PI</span> <span class="o">*</span> <span class="n">KARE</span><span class="p">(</span><span class="n">yaricap</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Parantezler önemlidir. <code class="language-plaintext highlighter-rouge">#define KARE(x) x * x</code> yazılsaydı <code class="language-plaintext highlighter-rouge">KARE(a + 1)</code> ifadesi <code class="language-plaintext highlighter-rouge">a + 1 * a + 1</code> biçiminde genişleyerek işlem önceliği hatası oluştururdu.</p>

<p>Makroların tür denetimi yapmadığı ve yalnızca metin değiştirdiği unutulmamalıdır. Ayrıca <code class="language-plaintext highlighter-rouge">KARE(i++)</code> gibi bir kullanım, argümanı iki kez değerlendirebilir. Bu durumda beklenmeyen yan etkiler ortaya çıkar. Tür güvenliği ve tek değerlendirme gerektiğinde <code class="language-plaintext highlighter-rouge">inline</code> fonksiyon genellikle daha iyi bir seçimdir.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>Makro</th>
      <th><code class="language-plaintext highlighter-rouge">inline</code> fonksiyon</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Tür denetimi</td>
      <td>Yok</td>
      <td>Var</td>
    </tr>
    <tr>
      <td>Argüman değerlendirmesi</td>
      <td>Birden fazla olabilir</td>
      <td>Bir kez</td>
    </tr>
    <tr>
      <td>Çalıştığı aşama</td>
      <td>Önişleme</td>
      <td>Derleme</td>
    </tr>
    <tr>
      <td>Hata ayıklama</td>
      <td>Daha zor</td>
      <td>Daha kolay</td>
    </tr>
  </tbody>
</table>

<h2 id="koşullu-derleme">Koşullu derleme</h2>

<p>Koşullu direktifler, platforma veya yapılandırmaya göre farklı kodların derlenmesini sağlar:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#ifdef DEBUG
</span>    <span class="n">printf</span><span class="p">(</span><span class="s">"Hata ayıklama modu etkin</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="cp">#endif
</span>
<span class="cp">#if defined(_WIN32)
</span>    <span class="n">printf</span><span class="p">(</span><span class="s">"Windows üzerinde çalışıyor</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="cp">#elif defined(__linux__)
</span>    <span class="n">printf</span><span class="p">(</span><span class="s">"Linux üzerinde çalışıyor</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="cp">#else
</span>    <span class="n">printf</span><span class="p">(</span><span class="s">"Bilinmeyen platform</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="cp">#endif
</span></code></pre></div></div>

<p>Komut satırından bir makro tanımlamak da mümkündür:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc <span class="nt">-DDEBUG</span> program.c <span class="nt">-o</span> program
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">#undef DEBUG</code> ise daha önce tanımlanmış makroyu kaldırır. Önişlemci ifadelerinde <code class="language-plaintext highlighter-rouge">defined</code>, mantıksal operatörler ve tamsayı sabitleri kullanılabilir; ancak normal C değişkenleri kullanılamaz. Çünkü değişkenler henüz derleyici tarafından işlenmemiştir.</p>

<p>Sonuç olarak C önişlemcisi güçlü fakat dikkatsiz kullanıldığında şaşırtıcıdır. Makroları küçük ve parantezli tutmak, include guard kullanmak, koşullu derlemeyi belgeli yürütmek ve mümkün olduğunda sabitler ile <code class="language-plaintext highlighter-rouge">inline</code> fonksiyonları tercih etmek daha okunabilir, taşınabilir ve güvenli programlar üretir.</p>

<p><img src="/img/c-onislemci-komutlari-51.svg" alt="c-onislemci-komutlari-51" /></p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="c" /><category term="önişlemci" /><category term="makro" /><category term="koşullu-derleme" /><category term="gcc" /><category term="programlama" /><summary type="html"><![CDATA[C dilinde kaynak kod, doğrudan makine koduna çevrilmez; önce birkaç aşamadan geçen küçük bir yolculuğa çıkar. Önişlemci, bu yolculuğun derlemeden hemen önceki durağıdır. #include, #define ve #if gibi direktifleri işler; başlık dosyalarını ekler, makroları genişletir ve hangi kod parçalarının derleyiciye ulaşacağını belirler. Kısacası önişlemci, sahne açılmadan önce dekoru hazırlayan görünmez bir ekip gibidir.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/c-onislemci-komutlari-51.png" /><media:content medium="image" url="https://program.sonsuz.us/img/c-onislemci-komutlari-51.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">C++ Şablonlar: Türlerden Bağımsız Jenerik Kod Yazmak</title><link href="https://program.sonsuz.us/posts/c-sablonlar-turlerden-bagimsiz-jenerik-kod-yazmak/" rel="alternate" type="text/html" title="C++ Şablonlar: Türlerden Bağımsız Jenerik Kod Yazmak" /><published>2026-10-19T00:00:00+00:00</published><updated>2026-10-19T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/c-sablonlar-turlerden-bagimsiz-jenerik-kod-yazmak</id><content type="html" xml:base="https://program.sonsuz.us/posts/c-sablonlar-turlerden-bagimsiz-jenerik-kod-yazmak/"><![CDATA[<p>Aynı toplama, karşılaştırma veya sıralama işlemini <code class="language-plaintext highlighter-rouge">int</code>, <code class="language-plaintext highlighter-rouge">double</code> ve başka veri türleri için tekrar tekrar yazmak pek eğlenceli değildir. C++ şablonları, algoritmayı bir kez tanımlayıp onu farklı türlerle kullanmamızı sağlar. Böylece derleyici, ihtiyaç duyulan türe uygun kodu bizim için üretir; biz de kopyala-yapıştır bataklığından kurtuluruz.
``</p>
<h2 id="şablonların-temel-mantığı">Şablonların temel mantığı</h2>

<p>Şablon, henüz kesinleşmemiş bir türü veya değeri parametre olarak alan kod kalıbıdır. <code class="language-plaintext highlighter-rouge">T</code> gibi bir şablon parametresi başlangıçta gerçek bir tür değildir; derleme sırasında <code class="language-plaintext highlighter-rouge">int</code>, <code class="language-plaintext highlighter-rouge">double</code> veya kullanıcı tarafından tanımlanmış bir sınıfla değiştirilir.</p>

<p>Bunu matematikteki genel bir fonksiyona benzetebiliriz:</p>

\[f(x, y) = x + y\]

<p>Burada toplama işlemi, $x$ ve $y$ değerlerinin türünden çok <code class="language-plaintext highlighter-rouge">+</code> operatörünü destekleyip desteklemediğiyle ilgilenir. Şablonlar da benzer biçimde çalışır. Bir tür, şablonun kullandığı işlemleri sağlıyorsa o şablonla kullanılabilir.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Avantaj</th>
      <th>Dezavantaj</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Her tür için ayrı fonksiyon</td>
      <td>Okuması kolaydır</td>
      <td>Kod tekrarı oluşturur</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">void*</code> kullanımı</td>
      <td>Türden bağımsız görünebilir</td>
      <td>Tür güvenliği zayıftır</td>
    </tr>
    <tr>
      <td>Şablon kullanımı</td>
      <td>Tür güvenli ve yeniden kullanılabilirdir</td>
      <td>Hata mesajları karmaşık olabilir</td>
    </tr>
  </tbody>
</table>

<h2 id="fonksiyon-şablonları">Fonksiyon şablonları</h2>

<p>İki değerden büyük olanı döndüren jenerik bir fonksiyon yazalım:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;string&gt;</span><span class="cp">
</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="nc">T</span><span class="p">&gt;</span>
<span class="n">T</span> <span class="nf">buyukOlan</span><span class="p">(</span><span class="k">const</span> <span class="n">T</span><span class="o">&amp;</span> <span class="n">a</span><span class="p">,</span> <span class="k">const</span> <span class="n">T</span><span class="o">&amp;</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">(</span><span class="n">a</span> <span class="o">&gt;</span> <span class="n">b</span><span class="p">)</span> <span class="o">?</span> <span class="n">a</span> <span class="o">:</span> <span class="n">b</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">buyukOlan</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mi">7</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="sc">'\n'</span><span class="p">;</span>
    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">buyukOlan</span><span class="p">(</span><span class="mf">3.4</span><span class="p">,</span> <span class="mf">8.1</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="sc">'\n'</span><span class="p">;</span>
    <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">buyukOlan</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">(</span><span class="s">"Ali"</span><span class="p">),</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">(</span><span class="s">"Zeynep"</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">template &lt;typename T&gt;</code> ifadesi, <code class="language-plaintext highlighter-rouge">T</code> adlı bir tür parametresi tanımlar. Derleyici ilk çağrıda <code class="language-plaintext highlighter-rouge">T = int</code>, ikinci çağrıda <code class="language-plaintext highlighter-rouge">T = double</code> kabul eder. Bu işleme <strong>şablon örnekleme</strong> denir. Kabaca üretilen fonksiyon sayısını şöyle düşünebiliriz:</p>

\[N_{üretilen} \approx N_{benzersiz\ tür\ birleşimi}\]

<p>Parametreleri <code class="language-plaintext highlighter-rouge">const T&amp;</code> ile almak, özellikle büyük nesnelerin gereksiz yere kopyalanmasını önler. Ancak kullanılan türün <code class="language-plaintext highlighter-rouge">&gt;</code> operatörünü desteklemesi gerekir; aksi hâlde derleme hatası alınır.</p>

<h2 id="birden-fazla-tür-parametresi">Birden fazla tür parametresi</h2>

<p>Bazen giriş türleri birbirinden farklı olabilir:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="nc">T</span><span class="p">,</span> <span class="k">typename</span> <span class="nc">U</span><span class="p">&gt;</span>
<span class="k">auto</span> <span class="nf">topla</span><span class="p">(</span><span class="k">const</span> <span class="n">T</span><span class="o">&amp;</span> <span class="n">a</span><span class="p">,</span> <span class="k">const</span> <span class="n">U</span><span class="o">&amp;</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">auto</span> <span class="n">sonuc</span> <span class="o">=</span> <span class="n">topla</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mf">2.5</span><span class="p">);</span> <span class="c1">// Sonuç double olur</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">auto</code> dönüş türünü <code class="language-plaintext highlighter-rouge">a + b</code> ifadesinden çıkarır. Böylece <code class="language-plaintext highlighter-rouge">int</code> ve <code class="language-plaintext highlighter-rouge">double</code> birlikte kullanılabilir. Yine de sonuç, ilgili türlerin birbirleriyle toplanabilmesine bağlıdır.</p>

<h2 id="sınıf-şablonları">Sınıf şablonları</h2>

<p>Şablonlar yalnızca fonksiyonlar için değildir. Farklı türlerde değer saklayabilen basit bir kutu sınıfı oluşturalım:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;utility&gt;</span><span class="cp">
</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="nc">T</span><span class="p">&gt;</span>
<span class="k">class</span> <span class="nc">Kutu</span> <span class="p">{</span>
<span class="nl">private:</span>
    <span class="n">T</span> <span class="n">deger</span><span class="p">;</span>

<span class="nl">public:</span>
    <span class="k">explicit</span> <span class="n">Kutu</span><span class="p">(</span><span class="n">T</span> <span class="n">yeniDeger</span><span class="p">)</span>
        <span class="o">:</span> <span class="n">deger</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">yeniDeger</span><span class="p">))</span> <span class="p">{}</span>

    <span class="k">const</span> <span class="n">T</span><span class="o">&amp;</span> <span class="n">getir</span><span class="p">()</span> <span class="k">const</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">deger</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kt">void</span> <span class="nf">ayarla</span><span class="p">(</span><span class="k">const</span> <span class="n">T</span><span class="o">&amp;</span> <span class="n">yeniDeger</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">deger</span> <span class="o">=</span> <span class="n">yeniDeger</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">};</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">Kutu</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">puan</span><span class="p">(</span><span class="mi">100</span><span class="p">);</span>
    <span class="n">Kutu</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span> <span class="n">mesaj</span><span class="p">(</span><span class="s">"Merhaba şablon!"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">Kutu&lt;int&gt;</code> ve <code class="language-plaintext highlighter-rouge">Kutu&lt;std::string&gt;</code>, aynı sınıf şablonundan üretilmiş farklı sınıf türleridir. Derleyici bunların her biri için uygun alanları ve metotları oluşturur.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>Fonksiyon şablonu</th>
      <th>Sınıf şablonu</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Tür çıkarımı</td>
      <td>Genellikle otomatik</td>
      <td>Çoğunlukla açıkça belirtilir</td>
    </tr>
    <tr>
      <td>Kullanım amacı</td>
      <td>Jenerik algoritmalar</td>
      <td>Jenerik veri yapıları</td>
    </tr>
    <tr>
      <td>Örnek</td>
      <td><code class="language-plaintext highlighter-rouge">buyukOlan(3, 5)</code></td>
      <td><code class="language-plaintext highlighter-rouge">Kutu&lt;int&gt;</code></td>
    </tr>
  </tbody>
</table>

<h2 id="dikkat-edilmesi-gerekenler">Dikkat edilmesi gerekenler</h2>

<p>Şablon tanımları çoğunlukla başlık dosyalarında bulunur. Çünkü derleyicinin belirli bir tür için kod üretirken şablonun tüm gövdesini görmesi gerekir. Ayrıca her tür, şablonda kullanılan operatörleri sağlamalıdır. Modern C++20 projelerinde bu beklentiler <code class="language-plaintext highlighter-rouge">concept</code> yapılarıyla açıkça ifade edilebilir.</p>

<p>Şablonlar; <code class="language-plaintext highlighter-rouge">std::vector</code>, <code class="language-plaintext highlighter-rouge">std::map</code> ve <code class="language-plaintext highlighter-rouge">std::sort</code> gibi Standart Kütüphane araçlarının temelidir. Kısacası doğru kullanıldıklarında daha az tekrar, güçlü tür güvenliği ve genişletilebilir kod sunarlar. Derleyici biraz daha çalışır, fakat programcı çok daha az terler!</p>

<p><img src="/img/c-sablonlar-turlerden-70.svg" alt="c-sablonlar-turlerden-70" /></p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="c++" /><category term="templates" /><category term="jenerik programlama" /><category term="fonksiyon şablonları" /><category term="sınıf şablonları" /><category term="programlama" /><summary type="html"><![CDATA[Aynı toplama, karşılaştırma veya sıralama işlemini int, double ve başka veri türleri için tekrar tekrar yazmak pek eğlenceli değildir. C++ şablonları, algoritmayı bir kez tanımlayıp onu farklı türlerle kullanmamızı sağlar. Böylece derleyici, ihtiyaç duyulan türe uygun kodu bizim için üretir; biz de kopyala-yapıştır bataklığından kurtuluruz.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/c-sablonlar-turlerden-70.png" /><media:content medium="image" url="https://program.sonsuz.us/img/c-sablonlar-turlerden-70.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">C# ve .NET Mimarisinin Temelleri: Kaynak Koddan CLR’a Yolculuk</title><link href="https://program.sonsuz.us/posts/c-ve-net-mimarisinin-temelleri-kaynak-koddan-clra-yolculuk/" rel="alternate" type="text/html" title="C# ve .NET Mimarisinin Temelleri: Kaynak Koddan CLR’a Yolculuk" /><published>2026-10-19T00:00:00+00:00</published><updated>2026-10-19T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/c-ve-net-mimarisinin-temelleri-kaynak-koddan-clra-yolculuk</id><content type="html" xml:base="https://program.sonsuz.us/posts/c-ve-net-mimarisinin-temelleri-kaynak-koddan-clra-yolculuk/"><![CDATA[<p>Bir C# programında <code class="language-plaintext highlighter-rouge">Console.WriteLine</code> yazıp çalıştır düğmesine bastığımızda perde arkasında küçük bir teknoloji festivali başlar. Kaynak kod derlenir, ara dile çevrilir, çalışma zamanı tarafından incelenir ve makine koduna dönüştürülür. C# ile .NET arasındaki ilişkiyi anlamak; performans, hata ayıklama ve taşınabilirlik gibi konuları ezberden değil, sağlam bir mimari üzerinden değerlendirmeyi sağlar.</p>

<p>``</p>

<h2 id="c-nereden-geldi">C# nereden geldi?</h2>

<p>C#, Microsoft tarafından .NET platformunun temel dillerinden biri olarak geliştirildi. Dilin baş mimarı Anders Hejlsberg’dir; ilk sürüm 2000 yılında duyurulmuş, .NET Framework ile birlikte 2002 yılında yaygın kullanıma açılmıştır. C++, Java ve Delphi gibi dillerden fikirler taşısa da zamanla kendine özgü, modern bir kimlik kazanmıştır.</p>

<p>C# başlangıçta Windows uygulamalarıyla özdeşleşse de günümüzde açık kaynaklı ve platformlar arası .NET üzerinde çalışır. Web uygulamalarından oyunlara, masaüstü yazılımlarından bulut servislerine kadar geniş bir kullanım alanına sahiptir.</p>

<table>
  <thead>
    <tr>
      <th>Kavram</th>
      <th>C#</th>
      <th>.NET</th>
      <th>CLR</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Temel görevi</td>
      <td>Programlama dili sunmak</td>
      <td>Geliştirme platformu sağlamak</td>
      <td>Kodu çalıştırmak</td>
    </tr>
    <tr>
      <td>İçeriği</td>
      <td>Sözdizimi ve dil kuralları</td>
      <td>Kütüphaneler, araçlar ve çalışma zamanı</td>
      <td>JIT, GC ve tür güvenliği</td>
    </tr>
    <tr>
      <td>Benzetme</td>
      <td>Tarif</td>
      <td>Mutfak</td>
      <td>Aşçı</td>
    </tr>
  </tbody>
</table>

<p><img src="/img/c-ve-net-45.svg" alt="c-ve-net-45" /></p>

<p>Bu ayrım önemlidir: C# bir <strong>dildir</strong>, .NET bir <strong>platformdur</strong>, CLR ise bu platformun çalışma zamanı motorudur.</p>

<h2 id="derleme-süreci-nasıl-işler">Derleme süreci nasıl işler?</h2>

<p>C# kaynak kodu doğrudan işlemcinin anlayacağı makine koduna çevrilmez. Önce Roslyn derleyicisi tarafından <strong>Common Intermediate Language</strong> olarak bilinen CIL’e dönüştürülür. CIL, işlemciden büyük ölçüde bağımsız bir ara dildir. Derleme sonucunda <code class="language-plaintext highlighter-rouge">.dll</code> veya <code class="language-plaintext highlighter-rouge">.exe</code> uzantılı bir <strong>assembly</strong> oluşur.</p>

<p>Bir assembly yalnızca CIL komutlarını içermez. Türler, metotlar, sürüm bilgileri ve bağımlılıklar gibi <strong>metadata</strong> bilgilerini de taşır. Çalıştırma sırasında CLR içindeki Just-In-Time derleyicisi, ihtiyaç duyulan metotların CIL kodunu hedef işlemcinin makine koduna çevirir.</p>

<p>Süreci şöyle özetleyebiliriz:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>C# kaynak kodu
      ↓ Roslyn
CIL + metadata içeren assembly
      ↓ CLR ve JIT
Makine kodu
      ↓
İşlemci
</code></pre></div></div>

<p>Toplam çalışma maliyeti basitleştirilmiş biçimde şu şekilde düşünülebilir:</p>

\[T_{toplam} = T_{yükleme} + T_{JIT} + T_{çalıştırma}\]

<p>JIT maliyeti ilk çağrıda hissedilebilir; ancak üretilen yerel kod sonraki çağrılarda yeniden kullanılabilir. .NET ayrıca uygulamayı önceden yerel koda yaklaştıran ReadyToRun ve Native AOT gibi seçenekler de sunar.</p>

<h2 id="clr-hangi-işleri-üstlenir">CLR hangi işleri üstlenir?</h2>

<p>CLR, yalnızca kodu çalıştıran pasif bir katman değildir. Bellek yönetimi, hata işleme, güvenlik kontrolleri, iş parçacıkları ve tür güvenliği gibi sorumlulukları üstlenir. En bilinen bileşenlerinden biri <strong>Garbage Collector</strong>, yani çöp toplayıcıdır. Artık erişilemeyen nesnelerin belleğini otomatik olarak geri kazanır.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">System</span><span class="p">;</span>

<span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">Urun</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Ad</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">decimal</span> <span class="n">Fiyat</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>

    <span class="k">public</span> <span class="nf">Urun</span><span class="p">(</span><span class="kt">string</span> <span class="n">ad</span><span class="p">,</span> <span class="kt">decimal</span> <span class="n">fiyat</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">Ad</span> <span class="p">=</span> <span class="n">ad</span><span class="p">;</span>
        <span class="n">Fiyat</span> <span class="p">=</span> <span class="n">fiyat</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="kt">decimal</span> <span class="nf">KdvliFiyat</span><span class="p">(</span><span class="kt">decimal</span> <span class="n">oran</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="n">Fiyat</span> <span class="p">*</span> <span class="p">(</span><span class="m">1</span> <span class="p">+</span> <span class="n">oran</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">var</span> <span class="n">urun</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Urun</span><span class="p">(</span><span class="s">"Klavye"</span><span class="p">,</span> <span class="m">1200m</span><span class="p">);</span>
<span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="n">urun</span><span class="p">.</span><span class="nf">KdvliFiyat</span><span class="p">(</span><span class="m">0.20m</span><span class="p">));</span>
</code></pre></div></div>

<p>Bu örnekte <code class="language-plaintext highlighter-rouge">Urun</code> nesnesi yönetilen bellekte oluşturulur. CLR nesnenin yaşam döngüsünü izler; nesneye erişim kalmadığında ayrılan alan GC tarafından temizlenebilir. Geliştiricinin çoğu durumda belleği elle serbest bırakması gerekmez.</p>

<h2 id="cts-ve-cls-neden-önemlidir">CTS ve CLS neden önemlidir?</h2>

<p><strong>Common Type System</strong>, .NET dillerinin ortak tür modelini tanımlar. Örneğin C# dilindeki <code class="language-plaintext highlighter-rouge">int</code>, CLR düzeyinde <code class="language-plaintext highlighter-rouge">System.Int32</code> türüne karşılık gelir. <strong>Common Language Specification</strong> ise farklı .NET dillerinin birbiriyle uyumlu çalışabilmesi için takip etmesi gereken kuralları belirler.</p>

<table>
  <thead>
    <tr>
      <th>Bileşen</th>
      <th>Sağladığı avantaj</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>CIL</td>
      <td>İşlemci bağımsız ara temsil</td>
    </tr>
    <tr>
      <td>Metadata</td>
      <td>Tür ve bağımlılık bilgilerinin taşınması</td>
    </tr>
    <tr>
      <td>JIT</td>
      <td>Hedef sisteme uygun makine kodu</td>
    </tr>
    <tr>
      <td>GC</td>
      <td>Otomatik bellek yönetimi</td>
    </tr>
    <tr>
      <td>CTS ve CLS</td>
      <td>Diller arası uyumluluk</td>
    </tr>
  </tbody>
</table>

<p>Sonuç olarak C# kodu tek başına yolculuk etmez. Roslyn, CIL, assembly, JIT ve CLR katmanları birlikte çalışarak taşınabilir, güvenli ve yönetilebilir bir yürütme ortamı oluşturur. Bu mimariyi bilmek, yalnızca kod yazmayı değil, kodun gerçekte nasıl hayata geçtiğini de anlamaktır.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="csharp" /><category term="dotnet" /><category term="clr" /><category term="derleme" /><category term="jit" /><category term="programlama" /><summary type="html"><![CDATA[Bir C# programında Console.WriteLine yazıp çalıştır düğmesine bastığımızda perde arkasında küçük bir teknoloji festivali başlar. Kaynak kod derlenir, ara dile çevrilir, çalışma zamanı tarafından incelenir ve makine koduna dönüştürülür. C# ile .NET arasındaki ilişkiyi anlamak; performans, hata ayıklama ve taşınabilirlik gibi konuları ezberden değil, sağlam bir mimari üzerinden değerlendirmeyi sağlar.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/c-ve-net-45.png" /><media:content medium="image" url="https://program.sonsuz.us/img/c-ve-net-45.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Cron Çalışıyor Ama Script Çalışmıyor: PATH ve Ortam Değişkenleri Tuzağı</title><link href="https://program.sonsuz.us/posts/cron-calisiyor-ama-script-calismiyor-path-ve-ortam-degiskenleri-tuzagi/" rel="alternate" type="text/html" title="Cron Çalışıyor Ama Script Çalışmıyor: PATH ve Ortam Değişkenleri Tuzağı" /><published>2026-10-19T00:00:00+00:00</published><updated>2026-10-19T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/cron-calisiyor-ama-script-calismiyor-path-ve-ortam-degiskenleri-tuzagi</id><content type="html" xml:base="https://program.sonsuz.us/posts/cron-calisiyor-ama-script-calismiyor-path-ve-ortam-degiskenleri-tuzagi/"><![CDATA[<p>Terminalde kusursuz çalışan bir script’in cron tarafından başlatıldığında hata vermesi, Linux dünyasının klasik “ama benim makinemde çalışıyordu” vakalarındandır. Suç çoğu zaman cron’da değil; interaktif shell ile cron job’ının farklı <code class="language-plaintext highlighter-rouge">PATH</code>, çalışma dizini ve ortam değişkenleri kullanmasındadır.
``</p>
<h2 id="aynı-kullanıcı-neden-farklı-sonuç">Aynı kullanıcı, neden farklı sonuç?</h2>

<p>Terminal açtığımızda Bash genellikle <code class="language-plaintext highlighter-rouge">.bashrc</code>, <code class="language-plaintext highlighter-rouge">.profile</code> veya <code class="language-plaintext highlighter-rouge">.bash_profile</code> gibi başlangıç dosyalarını okuyabilir. Bu dosyalar <code class="language-plaintext highlighter-rouge">PATH</code>, dil ayarları, alias’lar ve uygulamalara özel değişkenler tanımlar. Cron ise öngörülebilir olmak amacıyla oldukça sade bir ortam oluşturur ve interaktif shell yapılandırmasını kendiliğinden yüklemez.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>İnteraktif shell</th>
      <th>Cron ortamı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">PATH</code></td>
      <td>Genellikle genişletilmiş</td>
      <td>Kısa ve sistem odaklı</td>
    </tr>
    <tr>
      <td>Başlangıç dosyaları</td>
      <td>Çoğunlukla okunur</td>
      <td>Genellikle okunmaz</td>
    </tr>
    <tr>
      <td>Çalışma dizini</td>
      <td>Kullanıcının seçtiği dizin</td>
      <td>Çoğu zaman kullanıcının ev dizini</td>
    </tr>
    <tr>
      <td>Alias ve fonksiyonlar</td>
      <td>Kullanılabilir</td>
      <td>Genellikle tanımsız</td>
    </tr>
    <tr>
      <td>TTY</td>
      <td>Vardır</td>
      <td>Yoktur</td>
    </tr>
    <tr>
      <td>Dil değişkenleri</td>
      <td>Kullanıcı ayarlarından gelir</td>
      <td>Eksik veya farklı olabilir</td>
    </tr>
  </tbody>
</table>

<p><img src="/img/cron-calisiyor-ama-55.svg" alt="cron-calisiyor-ama-55" /></p>

<p>Shell bir komutun içinde <code class="language-plaintext highlighter-rouge">/</code> görmezse çalıştırılabilir dosyayı <code class="language-plaintext highlighter-rouge">PATH</code> dizinlerinde sırayla arar. Bunu basitçe şöyle düşünebiliriz:</p>

\[\text{komut yolu} = \min\{d_i/komut \mid d_i \in PATH,\; çalıştırılabilir\}\]

<p>Örneğin terminalinizde <code class="language-plaintext highlighter-rouge">/usr/local/bin</code> mevcutken cron’un <code class="language-plaintext highlighter-rouge">PATH</code> değerinde bu dizin yoksa <code class="language-plaintext highlighter-rouge">node</code>, <code class="language-plaintext highlighter-rouge">python</code>, <code class="language-plaintext highlighter-rouge">docker</code> veya özel bir CLI bulunamayabilir. Sonuç genellikle <code class="language-plaintext highlighter-rouge">command not found</code> olur; çıktı yönlendirilmediyse hatayı görmeyebilirsiniz bile.</p>

<h2 id="güvenilir-çözüm-ortamı-açıkça-tanımlamak">Güvenilir çözüm: ortamı açıkça tanımlamak</h2>

<p>Crontab içinde ihtiyaç duyulan shell ve <code class="language-plaintext highlighter-rouge">PATH</code> değerlerini belirtmek ilk savunma hattıdır:</p>

<pre><code class="language-cron">SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin

*/10 * * * * /home/ada/scripts/rapor.sh &gt;&gt; /home/ada/logs/rapor.log 2&gt;&amp;1
</code></pre>

<p>Buradaki <code class="language-plaintext highlighter-rouge">2&gt;&amp;1</code>, standart hata akışını standart çıktıyla aynı log dosyasına gönderir. Böylece cron’un sessizliğini bozup gerçek hatayı yakalayabilirsiniz. Ancak <code class="language-plaintext highlighter-rouge">SHELL=/bin/bash</code> yazmak Bash’i otomatik olarak login veya interaktif shell yapmaz; <code class="language-plaintext highlighter-rouge">.bashrc</code> dosyasının okunacağı anlamına gelmez.</p>

<p>Script içinde kritik komutlar için mutlak yollar kullanmak daha da sağlamdır:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/usr/bin/env bash</span>
<span class="nb">set</span> <span class="nt">-euo</span> pipefail

<span class="nv">DATE</span><span class="o">=</span>/usr/bin/date
<span class="nv">PG_DUMP</span><span class="o">=</span>/usr/bin/pg_dump
<span class="nv">GZIP</span><span class="o">=</span>/usr/bin/gzip

<span class="nv">backup</span><span class="o">=</span><span class="s2">"/var/backups/app-</span><span class="si">$(</span><span class="nv">$DATE</span> +%F<span class="si">)</span><span class="s2">.sql.gz"</span>
<span class="nv">$PG_DUMP</span> appdb <span class="se">\v</span>ert  <span class="nv">$GZIP</span> <span class="o">&gt;</span> <span class="s2">"</span><span class="nv">$backup</span><span class="s2">"</span>
</code></pre></div></div>

<p>Bu script, hangi programların çalışacağını belirsiz <code class="language-plaintext highlighter-rouge">PATH</code> aramasına bırakmaz. <code class="language-plaintext highlighter-rouge">set -euo pipefail</code> ise başarısız komutları, tanımsız değişkenleri ve boru hattı hatalarını görünür kılar.</p>

<h2 id="göreli-yolların-gizli-tehlikesi">Göreli yolların gizli tehlikesi</h2>

<p>Script’in <code class="language-plaintext highlighter-rouge">./config.json</code> dosyasını okuması, cron’un doğru dizinde başladığını garanti etmez. Önce script dizinine geçmek güvenlidir:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/usr/bin/env bash</span>
<span class="nb">set</span> <span class="nt">-euo</span> pipefail

<span class="nv">SCRIPT_DIR</span><span class="o">=</span><span class="s2">"</span><span class="si">$(</span><span class="nb">cd</span> <span class="nt">--</span> <span class="s2">"</span><span class="si">$(</span><span class="nb">dirname</span> <span class="nt">--</span> <span class="s2">"</span><span class="k">${</span><span class="nv">BASH_SOURCE</span><span class="p">[0]</span><span class="k">}</span><span class="s2">"</span><span class="si">)</span><span class="s2">"</span> <span class="o">&amp;&amp;</span> <span class="nb">pwd</span><span class="si">)</span><span class="s2">"</span>
<span class="nb">cd</span> <span class="s2">"</span><span class="nv">$SCRIPT_DIR</span><span class="s2">"</span>

/usr/bin/python3 generate_report.py <span class="nt">--config</span> ./config.json
</code></pre></div></div>

<p>Böylece script nereden çağrılırsa çağrılsın dosya yolları tutarlı kalır.</p>

<h2 id="ortamı-karşılaştırarak-hata-ayıklama">Ortamı karşılaştırarak hata ayıklama</h2>

<p>Cron’un gördüğü ortamı dosyaya yazdırabilirsiniz:</p>

<pre><code class="language-cron">* * * * * /usr/bin/env | /usr/bin/sort &gt; /tmp/cron-env.txt 2&gt;&amp;1
</code></pre>

<p>Terminalde de <code class="language-plaintext highlighter-rouge">env | sort &gt; /tmp/shell-env.txt</code> çalıştırıp iki dosyayı <code class="language-plaintext highlighter-rouge">diff</code> ile karşılaştırın. Ayrıca <code class="language-plaintext highlighter-rouge">command -v python3</code>, <code class="language-plaintext highlighter-rouge">command -v node</code> gibi komutlarla gerçek çalıştırılabilir yolları bulun.</p>

<p><code class="language-plaintext highlighter-rouge">.bashrc</code> dosyasını zorla yüklemek kısa vadede işe yarayabilir, fakat interaktif terminale özel komutlar cron altında yeni sorunlar çıkarabilir. En iyi yaklaşım; bağımlılıkları, yolları, çalışma dizinini ve loglamayı açıkça tanımlayan, kendi ortamını bilen bağımsız script’ler yazmaktır. Cron sürpriz yapmaz; yalnızca bizim terminalde fark etmeden taşıdığımız görünmez bagajı yanında getirmez.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="cron" /><category term="shell" /><category term="linux" /><category term="path" /><category term="bash" /><category term="hata ayıklama" /><summary type="html"><![CDATA[Terminalde kusursuz çalışan bir script’in cron tarafından başlatıldığında hata vermesi, Linux dünyasının klasik “ama benim makinemde çalışıyordu” vakalarındandır. Suç çoğu zaman cron’da değil; interaktif shell ile cron job’ının farklı PATH, çalışma dizini ve ortam değişkenleri kullanmasındadır.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/cron-calisiyor-ama-55.png" /><media:content medium="image" url="https://program.sonsuz.us/img/cron-calisiyor-ama-55.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>