İçeriğe geç

Menü

Berk Akademi
Yorumlar Google yorumları Özel Ders Başvuru Ücretsiz ön görüşme Ana Sayfa

C++ “undefined reference to” Linker Hatası Nasıl Çözülür?

cpp-undefined-reference-to-linker-hatasi-nasil-cozulur
Bu yazıda neler var?
  1. undefined reference to hatası hangi aşamada oluşur?
  2. Üç dosyalı örnekte eksik kaynak dosyası nasıl bulunur?
  3. Sınıf üyesi tanımında Hesap:: neden gereklidir?
  4. Harici kütüphane bağlama komutuna nasıl eklenir?
  5. Hata mesajından eksik tanımı bulma yöntemi
  6. Başlık ve şablon dosyalarında hangi hatalar yapılır?
  7. Sık Sorulan Sorular

C++ “undefined reference to” linker hatası, kaynak kodu derlendikten sonra bağlama aşamasında ortaya çıkar. Çözüm için çağrılan fonksiyonun bildiriminin bulunduğunu, tanımının gerçekten yazıldığını ve tanımı içeren kaynak dosyasının ya da kütüphanenin g++ komutuna eklendiğini kontrol etmelisin.

Derleyici her kaynak dosyasını önce nesne dosyasına dönüştürür. Bağlayıcı ise bu nesne dosyalarını, fonksiyon tanımlarını ve gerekiyorsa kütüphaneleri birleştirerek çalıştırılabilir dosyayı oluşturur. GCC'nin bu aşamaları nasıl yürüttüğü resmî belgelerinde açıklanır.

undefined reference to hatası hangi aşamada oluşur?

undefined reference to hatası genellikle derleme sonrasında, bağlama aşamasında oluşur. Bildirim, bir fonksiyonun veya sınıf üyesinin adını ve imzasını derleyiciye tanıtan açıklamadır. Tanım ise bu işlevin gövdesini sağlayan koddur.

Derleyici bir çağrıyı gördüğünde bildirime bakarak çağrının sözdizimsel olarak geçerli olup olmadığını kontrol eder. Bağlayıcı daha sonra bu çağrının karşılık geldiği tanımı arar. Tanım bulunamazsa hata mesajında çağrılan sembolün adıyla birlikte undefined reference to ifadesi görünür.

int topla(int, int);        // bildirim

int sonuc = topla(2, 3);    // çağrı

int topla(int a, int b) {   // tanım
    return a + b;
}

Bu üç parça arasındaki ilişkiyi şöyle düşünebilirsin: bildirim, işlevin nasıl çağrılacağını söyler; çağrı bu işlevi kullanır; tanım ise yapılacak işlemi içerir. Bildirim ve çağrı bulunduğu hâlde tanım derleme sürecine katılmazsa, kaynak dosyası kendi içinde doğru görünebilir fakat çalıştırılabilir dosya oluşturulamaz.

Üç dosyalı örnekte eksik kaynak dosyası nasıl bulunur?

Üç dosyalı örnekte eksik kaynak dosyası nasıl bulunur?

main.cpp, hesap.h ve hesap.cpp dosyalarından oluşan küçük bir projede bildirimi başlık dosyasına, tanımı kaynak dosyasına, çağrıyı ise main.cpp dosyasına yerleştirebilirsin.

hesap.h

#ifndef HESAP_H
#define HESAP_H

int topla(int a, int b);

#endif

hesap.cpp

#include "hesap.h"

int topla(int a, int b) {
    return a + b;
}

main.cpp

#include <iostream>
#include "hesap.h"

int main() {
    std::cout << topla(2, 3) << 'n';
    return 0;
}

Bu projede yalnızca main.cpp dosyasını derleyip bağlamaya çalışırsan şu komut eksik kalır:

g++ main.cpp -o hesap

main.cpp içindeki bildirim derleyicinin çağrıyı tanımasına yeterlidir; ancak topla fonksiyonunun gövdesi hesap.cpp dosyasındadır. Bu dosya komuta eklenmediği için bağlayıcı gerekli tanımı bulamaz.

İki kaynak dosyasını birlikte derleyip bağlayan komut şöyledir:

g++ main.cpp hesap.cpp -o hesap

Bu komutun ardından oluşan program, 2 ile 3 değerlerini toplar ve ekrana 5 yazdırır. Hata mesajında topla gibi eksik sembol görünüyorsa, bu sembolün tanımını içeren hesap.cpp dosyasının derleme komutunda yer alıp almadığını kontrol etmelisin.

Sınıf üyesi tanımında Hesap:: neden gereklidir?

Bildirim, derleyiciye bir fonksiyonun varlığını ve imzasını haber verir. Tanım ise fonksiyonun gövdesini içerir. Bir sınıf üyesi dışarıda tanımlanırken, bu tanımın hangi sınıfa ait olduğunu Hesap:: kapsam belirteciyle belirtmek gerekir.

// hesap.h
class Hesap {
public:
    void hesapla();
};

Yukarıdaki bildirimde hesapla fonksiyonunun Hesap sınıfına ait olduğu belirtilir. hesap.cpp içinde kapsam belirteci unutulursa aşağıdaki kod sınıf üyesini tanımlamaz:

// Hatalı tanım
#include "hesap.h"

void hesapla() {
}

Bu kod, sınıfın dışında bulunan serbest bir hesapla fonksiyonu tanımlar. Hesap sınıfının bildirdiği üye fonksiyon ise hâlâ tanımsız kaldığı için bağlayıcı, programın istediği Hesap::hesapla sembolünü bulamayabilir.

// Doğru tanım
#include "hesap.h"

void Hesap::hesapla() {
}

Tanımı kontrol ederken başlık dosyasındaki bildirim ile .cpp dosyasındaki tanımı şu açılardan karşılaştır:

  • Dönüş türü aynı mı?
  • Fonksiyon adı aynı mı?
  • Parametrelerin sayısı, türü ve sırası aynı mı?
  • Tanımda doğru sınıf kapsamı, yani Hesap:: kullanılmış mı?
  • Bildirimde const gibi bir niteleyici varsa tanımda da korunmuş mu?

Harici kütüphane bağlama komutuna nasıl eklenir?

Harici kütüphane bağlama komutuna nasıl eklenir?

Bir başlık dosyasını #include ile eklemek, kütüphanenin derlenmiş tanımlarını çalıştırılabilir dosyaya kendiliğinden katmaz. Başlık dosyası derleyiciye bildirimleri sağlar; bağlayıcının ayrıca kütüphane dosyasını bulması ve bağlantı komutunda kullanması gerekir.

Harici kütüphane kullanımında şu üç noktayı ayrı ayrı kontrol et:

  1. Derleyicinin görebileceği başlık dosyası gerçekten mevcut mu?
  2. Kütüphane dosyasının bulunduğu klasör bağlayıcının arama yollarında mı?
  3. Kütüphaneyi seçen bağlantı seçeneği komuta eklenmiş mi?

-l<kitaplık-adı> seçeneği bağlayıcıya belirli bir kütüphaneyi aramasını söyler. -L<klasör> ise kütüphane aranırken kullanılacak ek klasörü belirtir. Örneğin nesne dosyaları hazırlandıktan sonra genel komut yapısı şöyle olabilir:

g++ main.o hesap.o -L<klasör> -l<kitaplık-adı> -o uygulama

Burada main.o ve hesap.o içinde kütüphaneden beklenen semboller bulunabilir. Bu nedenle kütüphane seçeneğini, onu kullanan nesne dosyalarından sonra yazmak güvenli bir alışkanlıktır. GNU bağlayıcısı, nesne dosyalarını ve kütüphaneleri komutta verilen sıraya göre işler; -L seçenekleri ise -l ile aranan kütüphaneler için arama yolu ekler.

Kütüphane dosyası bulunamıyorsa veya bağlantı seçeneği eksikse hata mesajında kütüphaneden beklenen semboller için undefined reference to ifadeleri görülebilir. Bu durumda yalnızca başlık dosyasının doğru yazıldığını kontrol etmek yeterli değildir; kütüphanenin bağlantı komutunda seçildiğini ve arama klasörünün doğru verildiğini de incelemek gerekir.

Hata mesajından eksik tanımı bulma yöntemi

undefined reference to ifadesinden sonra görünen sembol adı, bağlayıcının hangi tanımı bulamadığını gösterir. Bağlayıcı, derlenmiş dosyalardaki çağrıları gerçek fonksiyon gövdeleriyle eşleştirir. Bu nedenle önce sembolün serbest fonksiyona, sınıf üyesine veya harici kütüphane işlevine ait olduğunu belirlemek gerekir.

  1. Mesajdaki sembol adını oku ve fonksiyonun hangi dosyada çağrıldığını belirle.
  2. Fonksiyon bildirimini, yani adını, parametrelerini ve dönüş türünü yazan satırı ilgili başlık dosyasında bul.
  3. Fonksiyonun gövdesini içeren tanımı ara. Tanımın gerekli .cpp dosyasında bulunduğunu kontrol et.
  4. Bu .cpp dosyasının derleme komutunda veya gerçek proje yapılandırmasında yer aldığını doğrula. Dosyanın yalnızca klasörde bulunması yeterli değildir.
  5. Sembol bir kütüphane işleviyse ilgili bağlama seçeneğinin komuta eklendiğini kontrol et.
Belirti Olası neden Kontrol
Fonksiyon bildirimi bulunuyor, fakat tanım bulunamıyor. Fonksiyon gövdesi yazılmamış veya isim ve parametreler bildirimle eşleşmiyor. Başlık dosyasındaki bildirim ile .cpp dosyasındaki tanımı karşılaştır.
Mesajdaki sembol kendi yazdığın fonksiyona ait. Yalnızca main.cpp derleniyor olabilir. İlgili kaynak dosyasını da derleme komutuna ekle.
Sembol bir sınıf üyesi fonksiyonu gösteriyor. Tanımda Hesap:: gibi sınıf kapsamı öneki unutulmuş olabilir. Fonksiyon tanımının sınıf adı ve kapsam çözümleme operatörüyle başladığını kontrol et.
Sembol harici bir kütüphaneye ait. Başlık dosyası eklenmiş, fakat kütüphane bağlama seçeneği verilmemiş olabilir. Derleme komutundaki kütüphane ve kütüphane yolu seçeneklerini kontrol et.

Bir IDE kullanıyorsan kaynak dosyanın proje yapılandırmasına gerçekten eklendiğinden emin ol. Dosyayı proje klasörüne kopyalamak, onun otomatik olarak derleneceği anlamına gelmez.

Başlık ve şablon dosyalarında hangi hatalar yapılır?

Başlık dosyasını include etmek, oradaki fonksiyon bildirimini görünür kılar; fonksiyonun tanımını kendiliğinden projeye eklemez. Bildirim, derleyiciye fonksiyonun varlığını ve nasıl çağrılacağını söyler. Tanım ise çalıştırılacak gövdeyi içerir.

// hesap.h
int topla(int a, int b);

// hesap.cpp
int topla(int a, int b) {
    return a + b;
}

main.cpp içinde hesap.h ekli olsa bile hesap.cpp derleme komutuna alınmazsa bağlayıcı, topla fonksiyonunun gövdesini bulamaz. Başlık ve kaynak dosyasının aynı klasörde bulunması bu durumu değiştirmez.

Şablon fonksiyonlarda tanımın çoğu zaman şablonun kullanılacağı noktada görünür olması gerekir. Tanım yalnızca bir .cpp dosyasına bırakılır ve başka bir dosyada farklı türlerle kullanılırsa bağlayıcı eksik sembol bildirebilir.

template <typename T>
T kare(T deger) {
    return deger * deger;
}

Bu nedenle şablon bildirimi ve tanımı genellikle aynı başlık dosyasında tutulur. Teşhis sırası şöyledir: mesajdaki sembolü oku, bildirimi bul, tanımı ara, sınıf kapsamını kontrol et, ilgili .cpp dosyasını derle ve harici kütüphaneyi bağla. multiple definition of main ise aynı sembolün birden fazla tanımlanmasıyla ilgili farklı bir bağlama hatasıdır.

Sık Sorulan Sorular

Başlık dosyasını include etmek fonksiyonun tanımını da projeye ekler mi?

Başlık dosyasını include etmek çoğunlukla yalnızca bildirimi görünür yapar. Fonksiyon gövdesinin bulunduğu .cpp dosyası ayrıca derlenip bağlanmalıdır.

Neden yalnızca main.cpp dosyasını derlemek undefined reference to hatasına yol açar?

Yalnızca main.cpp derlendiğinde diğer kaynak dosyalarındaki fonksiyon tanımları oluşan programa eklenmez. Bu durumda bağlayıcı, çağrılan fonksiyon için gövde bulamaz.

C++ şablon fonksiyonunun tanımını neden çoğu zaman.cpp dosyasında bırakmamak gerekir?

Şablonun gerçek kodu, kullanıldığı tür bilindiğinde oluşturulur. Tanım görünür değilse derleyici gerekli örneği üretemeyebilir ve bağlama aşamasında eksik sembol oluşabilir.

Harici bir kütüphane kullanırken başlık dosyası ekli olduğu hâlde neden bağlama hatası alınabilir?

Başlık dosyası işlev bildirimlerini sağlar, ancak kütüphanenin derlenmiş kodunu programa eklemez. Bu nedenle gerekli kütüphane bağlama seçeneği ayrıca verilmelidir.

undefined reference to hatasını çözerken mesajdaki sembolü kaynak kodundaki bildirim ve tanımla eşleştirmen, ardından ilgili dosya ile kütüphanenin gerçekten bağlama sürecine katıldığını doğrulaman yeterli bir başlangıç sağlar.

Bu içerik aradığın cevabı verdi mi?
Yanıtın, hangi yazıları geliştirmemiz gerektiğini anlamamıza yardımcı olur.
Bu içeriğin üretilmesinde yapay zeka araçlarından destek alınmıştır.

Bu konudan sonra ne okuyabilirsin?

Tüm yazılar

İlgili Eğitimler

Berk Keskin, yazılım geliştirici ve eğitmen
Yazar

Berk Keskin Kimdir?

Yazılıma 12 yaşında başladı; İzmir Ekonomi Üniversitesi'ni bölüm birincisi ve yüksek şeref öğrencisi olarak tamamladı. Bugün yalnızca eğitim vermekle kalmıyor, sektörde aktif olarak yazılım projeleri geliştiriyor ve gerçek dünya deneyimini birebir derslerine taşıyor. Ezberden uzak, mühendislik zihniyetini merkeze alan sürdürülebilir öğrenme sistemleri tasarlayarak sorgulayan, üreten ve problem çözebilen yeni nesil yazılımcılar yetiştiriyor.

Sektörel Deneyim & Projeler

  • Ticarify Entegrasyon Yazılım logosu CEO Ticarify Entegrasyon YazılımPazaryerleri ve e-ticaret sitelerine otomatik e-fatura kesimi, sipariş ve kargo takibi hizmetleri sunan e-Dönüşüm platformunun API mimarisini ve yazılım ekibini yönetmektedir.
  • Benim Düğünüm logosu CEO Benim DüğünümDijital etkinlik ve anı paylaşım platformu.
  • Siberdizayn logosu Yazılım Ekibi Lideri SiberdizaynYüksek anlık oyuncu trafiğine sahip oyun kontrol panelleri ve sunucu altyapıları geliştiren yazılım ekibine liderlik etmektedir.
  • MEDYOGRAFYA 360° Dijital Çözümler logosu Dijital Strateji Lideri MEDYOGRAFYA 360° Dijital ÇözümlerŞirketlerin dijital çözümlerde uzun vadede nasıl ilerlemesi gerektiği ve dijital dönüşüm süreçlerinin yönetilmesine destek olmaktadır.
  • İzmir Ekonomi Üniversitesi logosu Danışma Kurulu Üyesi İzmir Ekonomi ÜniversitesiMezun olduğu üniversitesinde, Bilgisayar Programcılığı bölümünün akademik müfredatını güncel sektör ihtiyaçlarına göre şekillendirmek adına Danışma Kurulu'nda görev almaktadır.
WhatsApp Hemen Ara