Bu, Windows ve Unix benzeri sistemler arasında oldukça ünlü bir farktır.
Ne olursa olsun:
- Her işlemin kendi adres alanı vardır, yani işlemler arasında hiçbir zaman paylaşılan bellek yoktur (bazı işlemler arası iletişim kitaplığı veya uzantıları kullanmadığınız sürece).
- Bir Tanım Kuralı (ODR) hala sadece bağlantı süresi (statik veya dinamik bağlama) görünür küresel değişkenin bir tanımını sahip olabileceği anlamına geçerlidir.
Yani, buradaki temel sorun gerçekten görünürlük .
Her durumda, static
global değişkenler (veya işlevler) bir modülün dışından (dll / so veya çalıştırılabilir) asla görünmez. C ++ standardı, bunların dahili bağlantıya sahip olmasını gerektirir, yani tanımlandıkları çeviri biriminin dışında (bir nesne dosyası haline gelir) görünmezler. Yani, bu sorunu çözer.
extern
Küresel değişkenlere sahip olduğunuz zaman karmaşıklaşır . Burada Windows ve Unix benzeri sistemler tamamen farklıdır.
Windows (.exe ve .dll) durumunda, extern
genel değişkenler dışa aktarılan sembollerin parçası değildir. Başka bir deyişle, farklı modüller, diğer modüllerde tanımlanan global değişkenlerin hiçbir şekilde farkında değildir. Bu, örneğin, bir extern
DLL'de tanımlanmış bir değişkeni kullanması gereken bir yürütülebilir dosya oluşturmaya çalışırsanız, buna izin verilmediğinden, bağlayıcı hataları alacağınız anlamına gelir . Bu harici değişkenin tanımını içeren bir nesne dosyası (veya statik kitaplık) sağlamanız ve onu hem yürütülebilir dosya hem de DLL ile statik olarak bağlamanız gerekir ; bu, iki farklı genel değişkenle sonuçlanır (biri yürütülebilir dosyaya, diğeri de DLL'ye aittir. ).
Windows'ta global bir değişkeni gerçekten dışa aktarmak için, verme / alma sözdizimine benzer bir sözdizimi kullanmanız gerekir, yani:
#ifdef COMPILING_THE_DLL
#define MY_DLL_EXPORT extern "C" __declspec(dllexport)
#else
#define MY_DLL_EXPORT extern "C" __declspec(dllimport)
#endif
MY_DLL_EXPORT int my_global;
Bunu yaptığınızda, global değişken dışa aktarılan semboller listesine eklenir ve diğer tüm işlevler gibi bağlanabilir.
Unix benzeri ortamlarda (Linux gibi), uzantıya sahip "paylaşılan nesneler" olarak adlandırılan dinamik kitaplıklar .so
tüm extern
global değişkenleri (veya işlevleri) dışa aktarır. Bu durumda, herhangi bir yerden paylaşılan bir nesne dosyasına yükleme süresi bağlantısı yaparsanız , o zaman global değişkenler paylaşılır, yani tek olarak birbirine bağlanır. Temel olarak, Unix benzeri sistemler, statik veya dinamik bir kitaplıkla bağlanma arasında neredeyse hiç fark olmaması için bunu yapmak için tasarlanmıştır. Yine, ODR pano boyunca geçerlidir: extern
global bir değişken modüller arasında paylaşılacaktır, bu da yüklenen tüm modüller arasında yalnızca bir tanıma sahip olması gerektiği anlamına gelir.
Son olarak, her iki durumda da, Windows veya Unix benzeri sistemler için, dinamik kitaplığın çalışma anında bağlanmasını, yani LoadLibrary()
/ GetProcAddress()
/ FreeLibrary()
veya dlopen()
/ dlsym()
/ kullanarak yapabilirsiniz dlclose()
. Bu durumda, kullanmak istediğiniz sembollerin her birine manuel olarak bir işaretçi almanız gerekir ve bu, kullanmak istediğiniz global değişkenleri içerir. Global değişkenler için, global değişkenlerin dışa aktarılan sembol listesinin parçası olması koşuluyla (önceki paragrafların kurallarına göre), işlevler için kullandığınız gibi kullanabilirsiniz GetProcAddress()
veya dlsym()
aynısını kullanabilirsiniz .
Ve tabii ki, gerekli bir son not olarak: küresel değişkenlerden kaçınılmalıdır . Ve alıntı yaptığınız metnin ("net olmayan" şeyler hakkında) tam olarak az önce açıkladığım platforma özgü farklılıklara atıfta bulunduğuna inanıyorum (dinamik kitaplıklar gerçekten C ++ standardı tarafından tanımlanmamaktadır, bu platforma özgü bölgedir, yani çok daha az güvenilir / taşınabilir).