Arkadaslar extern kullanimini arastirdim ve yazdigi sey “bir degiskenin baska bir modulde tanimlandigini belirtmek icin kullaniliyor” yaziyordu, ne demek istedigini anladim ama neden kullanmaliyiz ne gerek var veya sadece belirtmeye mi yariyor??
X değişkeni Y modülünde var gibi mi?
Evet belirtmeye yariyormuş ama ne gerek var??
Aynı isim olması (sanmıyorum bu değil) veya oradaki değişkenlere müdahale edebiliyor olmamız.Veya bunda X var,bundaki X’i al gibi şeyler kullanmaz mısın?
extern kullanılması gereken bir örnek üzerinden
extern'i anlatmaya çalışayım.
Şimdi diyelim bir tane header dosyamız var. Bu dosyamızda da
global alanda görünecek bir adet fonksiyon tanımlamış olalım.
dosya.h
void foo();
Bu header dosyamızı bir kütüphane olarak
dosya.c isminde bir dosyanın içine aktaralım ve
foo fonksiyonunu kullanalım.
dosya.c
#include <stdio.h> #include "dosya.h" void foo() { printf("hello"); }
İki tane benzer program oluşturacağız. Bunların birincisi bir
C programı olacak, diğeri de bir
C++ programı olacak. Ve
C++ programında
extern'in nasıl kullanıldığını göreceğiz.
Ana
C programımızın ismi
main.c olsun.
main.c
#include "dosya.h" int main() { foo(); return 0; }
Bizim bu
main.c'yi derlemek için linkleme yapmamız gerekir. Yani doğrudan
main.c'yi derlemeye kalkışırsak
foo için tanımsız bir başvuru hatası alırız. Bu yüzden
c uzantılı dosyalarımızdan
obj dosyaları oluşturacağız.
gcc -c main.c && gcc -c dosya.c
Dizinimizde şimdi
main.o ve
dosya.o isminde iki adet
obj dosyası var. Ve bu dosyaları birbirlerine linkleyerek derlemek için şöyle bir komut yazıyoruz.
gcc main.o dosya.o -o dosyam
Artık oluşan
dosyam dosyasını çalıştırırsak, ekrana
hello yazısı yazdırılacaktır.
Diyebilirsiniz ki bunun
C++'daki
extern ile ne alakası var. Şimdi izninizle ona gelmek istiyorum. Az önce bahsettiğim gibi aynı programın bir de
C++ versiyonunu yapacağız. Dosyamızın ismi bu sefer
main.cpp olacak.
Önce kodları hiç değiştirmeden yazalım bakalım.
main.cpp
#include "dosya.h" int main() { foo(); return 0; }
Şimdi bu dosyanın
obj dosyasını oluşturalım.
g++ -c main.cpp
main.o dosyamız oluşacaktır.
Şimdi bu
dosya.o ile
main.o dosyamızı linkleyerek
dosyam'ı oluşturmaya çalışalım.
g++ main.o dosya.o -o dosyam
Bu durumda
foo'nun tanımsız olduğuna yönelik bir hata alacağız. İşte böyle bir hatayı önlemek için
extern anahtar sözcüğünü kullanmamız gerekiyor.
Dolayısıyla
main.cpp dosyamızda şöyle bir değişiklik yapıyoruz.
main.cpp
extern "C" { #include "dosya.h" } int main() { foo(); return 0; }
Dosyayı bu şekilde kaydettikten sonra tekrar bir
obj dosyası oluşturalım.
g++ -c main.cpp
Şimdi de bu iki dosyayı birbirine linklenmiş bir şekilde derleyelim.
g++ main.o dosya.o -o dosyam
Artık
g++ ile derlenen
dosyam, tıpkı
gcc ile derlenen
dosyam gibi aynı sonucu vererek çalışacaktır.
Burada
extern anahtar sözcüğünün kullanılmasının sebebini açıklamaya çalışayım.
main.cpp dosyasında
extern'i eklemeden önce oluşturulan
main.o dosyasının içinde neler olduğuna bakalım. Bunun için önce
main.cpp'nin içeriğini eski haline getiriyoruz ve
obj dosyası oluşturuyoruz. Sonra da aşağıdaki komutu çalıştırıyoruz.
nm main.o
Şuna benzer bir çıktı almamız gerekiyor:
U _GLOBAL_OFFSET_TABLE_ 0000000000000000 T main U _Z3foov
Burada gördüğünz gibi
foo fonksiyonunun ismi biraz farklı. Bu
foov ifadesindeki
v,
void olduğu için var ve bu ifade ile aslında linklemeye çalıştığımız fonksiyonun ismi birbirlerinden farklı.
dosya.o'nun içine bakalım.
nm dosya.o
Şöyle bir çıktı almamız gerekiyor:
0000000000000000 T foo U _GLOBAL_OFFSET_TABLE_ U puts
Biz
extern ifadesini kullanarak,
foo'nun isminin
C dosyasındaki gibi kalmasını sağlamış oluyoruz.
Bir de
extern edilmiş
main.cpp dosyamızın içerisine bakalım. Bunun için tabi önce yeni bir
obj dosyası oluşturmamız gerekiyor, çünkü dosyanın içeriğini değiştirmiştik.
nm main.o
Bu kez alacağımız çıktı şöyle olacaktır.
U foo U _GLOBAL_OFFSET_TABLE_ 0000000000000000 T main
Umarım anlatabilmişimdir.
Hocam simdi bi sorum var yukarda dosya.c yi nasil dosya.h olarak cagirdiniz
dosya.c'yi
dosya.h olarak çağırmadım.
dosya.h diye bir header dosyası oluşturdum. Sonra
dosya.h'ı
dosya.c dosyasına aktardım. Sonra
dosya.c dosyasından bir
obj dosyası oluşturdum.
main.c dosyasına
dosya.h'ı aktardım ve
main.c dosyasından da bir
obj dosyası oluşturdum. Sonra bu iki
obj dosyasını linkleyerek derledim. C++ için de benzer bir yol izlendi. Tek fark C++'da fonksiyonu tanımlı hale getirmek için
extern kullanmamız oldu.
Kafam karisti gibi ama saolun anlamaya calisirim xD
( @dildeolupbiten hocam si hangi kaynaktan ogreniyorsunuz c++ ı bir kac kaynak buldum ama merak ettim)
Hakikaten “modul” yaziyorsa okumayi birak—dogru terim compilation unit.
Degiskenin linkage’ini external yapiyor, define edilmeden declare edilmesini sagliyor. Fonksiyonlardaki
int hede(int); deklarasyonuyla ayni is yani. (Fonksiyonlarin default linkage’i external.)
Ayni zamanda
extern "C" gibi bir kullanimi var, o da ABI gibi diger linkage parametrelerini degistiriyor. Yukarida @dildeolupbiten ornegini vermis.
Örnekler üzerinden daha rahat anlarsınız diye düşünüyorum.
Bir tane header dosyamız var:
header.c
int topla(int x, int y);
Bu header dosyasını
linklenecek.c isminde bir dosyanın içine aktaracağız.
linklenecek.c
#include <stdio.h> #include "header.h" int topla(int x, int y) { printf("x + y = %d\n", x + y); return 0; }
Bir tane de
ana isminde bir C++ dosyamız var. İçinde de şunlar yazıyor:
ana.cpp
extern "C" { #include "header.h" } int main() { topla(2, 3); return 0; }
Şimdi siz bu haliyle
ana.cpp dosyasını program haline getirmeye çalışırsanız,
topla fonksiyonu için tanımsız başvuru hatası alırsınız. Çünkü
header dosyasında
topla fonksiyonunun ne tip değer döndürdüğünü ve hangi tipte kaç tane parametre aldığını tanımladık. Ama fonksiyonun nasıl bir işlem yapacağını tanımlamadık. Bu tanımlamayı
linklenecek.c ismindeki dosyamızda yapacağız. Dolayısıyla
ana.cpp dosyamızdaki
topla fonksiyonu ile
linklenecek.c dosyamızdaki
topla fonksiyonunun linklenmesi gerekiyor. Bunun için de hem
ana.cpp hem de
linklenecek.c dosyalarından
obj dosyaları oluşturuyoruz.
g++ -c ana.cpp && gcc -c linklenecek.c
Sonra da bu
obj dosyalarını birlikte derliyoruz.
g++ ana.o linklenecek.o -o dosyam
Linklemeye ihtiyaç duymadan yapamaz mıydık? Elbette yapardık, o zaman şöyle yapmamız gerekirdi:
header.h dosyamız.
int topla(int x, int y){ return x + y; }
ana.cpp dosyamız.
#include "header.h" #include <iostream> using namespace std; int main() { std::cout << "x + y = " << topla(2, 3) << "\n"; return 0; }
Böylece doğrudan
ana.cpp dosyamızı alıştığımız şekilde derlerdik.
İnanmayacaksın ama google sağ olsun benim takip ettiğim herhangi bir kaynak yok. Boşuna Hz. Google demiyorum.
Ya hocam biraz kizabilirsiniz ama son ornekteki externin amacini anlamadim orda extern demeseydik de zaten topla ya gorev yuklemedigimizden hata almicak miydik zaten :
Son örnek derken? Hangi örnekten bahsediyorsunuz? Son mesajımda
extern kullandığım örnekten mi?
Bu ornekte @dildeolupbiten
extern “C”
C++ içinde C kodu çalıştırabilmemize yarıyor sanırım.
https://isocpp.org/wiki/faq/mixing-c-and-cpp
Dediğiniz doğru. Daha spesifik olarak C++'ta kullacağınız bir fonksiyon adının C bağlantısına sahip olmasını sağlar.
Hayir, export edilenlerin C linkage’i ile export edilmesini, import edilenlerin de C linkage’ina sahip olmalarinin beklenmesini sagliyor.
Veya dedigine yaklasmak istersek: C++ icinden C kodunun cagrilabilmesine, ve tersine yariyor.
@aib’in dediği doğru aslında. Yani çalıştırılmasını sağlıyor ifadesi hatalı. Ben de doğru diyorsunuz diyerek hata yapmışım.
Aslında bu ifadeyi kullanarak anlatmak istediğiniz şey ile, bu ifadenin anlamı arasında tam bir örtüşme yok. Yine de anlatmak istediğinizi anlıyorum.
Toparlamaya çalışayım, yanlışım varsa da düzeltin lütfen.
extern "C", bir bağlantı belirtimidir. C++ dosyanız ile bir C dosyasını linkleyerek derlemeye çalıştığınızda,
extern "C" bağlantı belirtimini kullanarak, C dosyasında yer alan fonksiyonun adını, header dosyasının içindeki aynı ada sahip fonksiyonla bağlantılı hale getiriyor ve derleyicinin bu ismi karıştırmamasını sağlamış oluyoruz.
Kaynak dosyalari linklenerek derlenmiyor, obje dosyalarina derleniyorlar.
Daha sonra bu obje dosyalari linkleniyorlar.
C dosyasindan kast edilenin ne oldugundan emin degilim. C++ kaynak kodu veya extern “C” ile baglantisini da anlayabilmis degilim, icinde include mu ediyoruz dosyayi?
extern "C", icine aldigi declaration’larin obje dosyalarinda C linkage’i ile bulunmasini sagliyor. Name mangling cogu C++ linkage’inda olup cogu C linkage’inda olmayan bir sey.
Pardon ben obje dosyalarından bahsetmeyi unutmuşum.
Paragrafı aşağıdaki gibi değiştirirsek doğru mu ifade etmiş oluruz?
extern "C", bir bağlantı belirtimidir. C++ obje dosyası ile bir C obje dosyasını linkleyerek derlemeye çalıştığınızda,
extern "C"bağlantı belirtimini kullanarak, C objesinde yer alan fonksiyonun adını, header dosyasının içindeki aynı ada sahip fonksiyonla bağlantılı hale getiriyor ve derleyicinin bu ismi karıştırmamasını sağlamış oluyoruz.