Ini adalah perbedaan yang cukup terkenal antara sistem Windows dan mirip Unix.
Apa pun yang terjadi:
- Setiap proses memiliki ruang alamatnya sendiri, yang berarti bahwa tidak pernah ada memori yang dibagi antar proses (kecuali Anda menggunakan beberapa pustaka atau ekstensi komunikasi antar-proses).
- Aturan Satu Definisi (ODR) tetap berlaku, artinya Anda hanya dapat memiliki satu definisi variabel global yang terlihat pada waktu penautan (penautan statis atau dinamis).
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 menggunakan extern
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:
#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;
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 semua extern
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()
atau dlopen()
/ 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 menggunakan GetProcAddress()
atau dlsym()
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).