Saya mencoba memahami apa yang terjadi ketika modul dengan variabel global dan statis secara dinamis ditautkan ke aplikasi. Yang saya maksud dengan modul adalah setiap proyek dalam sebuah solusi (saya banyak bekerja dengan studio visual!). Modul-modul ini dibangun ke dalam * .lib atau * .dll atau * .exe itu sendiri.
Saya memahami bahwa biner aplikasi berisi data global dan statis dari semua unit terjemahan individual (file objek) di segmen data (dan hanya membaca segmen data jika const).
Apa yang terjadi jika aplikasi ini menggunakan modul A dengan penautan dinamis waktu muat? Saya berasumsi DLL memiliki bagian untuk global dan statika. Apakah sistem operasi memuatnya? Jika ya, ke mana mereka dimuat?
Dan apa yang terjadi jika aplikasi menggunakan modul B dengan tautan dinamis run-time?
Jika saya memiliki dua modul dalam aplikasi saya yang menggunakan A dan B, apakah salinan global A dan B dibuat seperti yang disebutkan di bawah (jika prosesnya berbeda)?
Apakah DLL A dan B mendapatkan akses ke aplikasi global?
(Harap sebutkan alasan Anda juga)
Mengutip dari MSDN :
Variabel yang dideklarasikan sebagai global dalam file kode sumber DLL diperlakukan sebagai variabel global oleh compiler dan linker, tetapi setiap proses yang memuat DLL tertentu mendapatkan salinannya sendiri dari variabel global DLL tersebut. Ruang lingkup variabel statis terbatas pada blok di mana variabel statis dideklarasikan. Akibatnya, setiap proses memiliki contoh sendiri dari variabel global dan statis DLL secara default.
dan dari sini :
Saat menautkan modul secara dinamis, tidak jelas apakah library yang berbeda memiliki instance globalnya sendiri atau apakah library tersebut dibagikan.
Terima kasih.
Jawaban:
Ini adalah perbedaan yang cukup terkenal antara sistem Windows dan mirip Unix.
Apa pun yang terjadi:
Jadi, masalah kuncinya di sini adalah visibilitas .
Dalam semua kasus,
static
variabel global (atau fungsi) tidak pernah terlihat dari luar modul (dll / so atau executable). Standar C ++ mensyaratkan bahwa ini memiliki hubungan internal, yang berarti bahwa mereka tidak terlihat di luar unit terjemahan (yang menjadi file objek) di mana mereka didefinisikan. Jadi, itu menyelesaikan masalah itu.Yang menjadi rumit adalah ketika Anda memiliki
extern
variabel global. Di sini, sistem Windows dan mirip Unix sama sekali berbeda.Dalam kasus Windows (.exe dan .dll),
extern
variabel global bukan bagian dari simbol yang diekspor. Dengan kata lain, modul yang berbeda sama sekali tidak mengetahui variabel global yang ditentukan dalam modul lain. Ini berarti Anda akan mendapatkan kesalahan penaut jika Anda mencoba, misalnya, untuk membuat file yang dapat dieksekusi yang seharusnya menggunakanextern
variabel yang ditentukan dalam DLL, karena ini tidak diperbolehkan. Anda akan perlu untuk memberikan file objek (atau perpustakaan statis) dengan definisi variabel ekstern dan link statis dengan baik dieksekusi dan DLL, mengakibatkan dua variabel yang berbeda global (satu milik executable dan satu milik DLL ).Untuk benar-benar mengekspor variabel global di Windows, Anda harus menggunakan sintaks yang mirip dengan sintaks fungsi ekspor / impor, yaitu:
Saat Anda melakukannya, variabel global ditambahkan ke daftar simbol yang diekspor dan dapat ditautkan seperti semua fungsi lainnya.
Dalam kasus lingkungan mirip Unix (seperti Linux), pustaka dinamis, yang disebut "objek bersama" dengan ekstensi
.so
mengekspor semuaextern
variabel global (atau fungsi). Dalam kasus ini, jika Anda melakukan penautan waktu muat dari mana saja ke file objek bersama, maka variabel global akan dibagikan, yaitu, ditautkan bersama sebagai satu. Pada dasarnya, sistem mirip Unix dirancang untuk membuatnya sehingga hampir tidak ada perbedaan antara menghubungkan dengan pustaka statis atau dinamis. Sekali lagi, ODR berlaku di seluruh papan:extern
variabel global akan dibagikan di seluruh modul, yang berarti hanya ada satu definisi di semua modul yang dimuat.Terakhir, dalam kedua kasus tersebut, untuk sistem Windows atau mirip Unix, Anda dapat melakukan penautan run-time dari pustaka dinamis, misalnya, menggunakan
LoadLibrary()
/GetProcAddress()
/FreeLibrary()
ataudlopen()
/dlsym()
/dlclose()
. Dalam hal ini, Anda harus secara manual mendapatkan pointer ke setiap simbol yang ingin Anda gunakan, dan itu termasuk variabel global yang ingin Anda gunakan. Untuk variabel global, Anda dapat menggunakanGetProcAddress()
ataudlsym()
sama seperti yang Anda lakukan untuk fungsi, asalkan variabel global adalah bagian dari daftar simbol yang diekspor (berdasarkan aturan paragraf sebelumnya).Dan tentu saja, sebagai catatan akhir yang diperlukan: variabel global harus dihindari . Dan saya percaya bahwa teks yang Anda kutip (tentang hal-hal yang "tidak jelas") merujuk persis pada perbedaan khusus platform yang baru saja saya jelaskan (perpustakaan dinamis tidak benar-benar ditentukan oleh standar C ++, ini adalah wilayah khusus platform, artinya itu jauh kurang andal / portabel).
sumber
__attribute__((visibility("default")))
), maka A / B akan berbagi st_var yang sama. Tetapi jika kelas ditentukan dengan__attribute__((visibility("hidden")))
, maka modul A dan modul B akan memiliki salinannya sendiri, tidak dibagikan.