นี่คือความแตกต่างที่มีชื่อเสียงมากระหว่าง Windows และระบบที่เหมือน Unix
ไม่ว่าอะไรก็ตาม:
- แต่ละกระบวนการมีพื้นที่แอดเดรสของตัวเองซึ่งหมายความว่าจะไม่มีการแชร์หน่วยความจำระหว่างโปรเซส (เว้นแต่คุณจะใช้ไลบรารีการสื่อสารระหว่างกระบวนการหรือส่วนขยาย)
- กฎข้อหนึ่ง Definition (ODR) ยังคงใช้ซึ่งหมายความว่าคุณสามารถมีได้เพียงหนึ่งความหมายของตัวแปรทั่วโลกสามารถมองเห็นได้ที่ลิงค์ไทม์ (คงที่หรือเชื่อมโยงแบบไดนามิก)
ดังนั้นปัญหาที่สำคัญที่นี่เป็นจริงการมองเห็น
ในทุกกรณีstatic
ตัวแปรส่วนกลาง (หรือฟังก์ชัน) จะไม่ปรากฏจากภายนอกโมดูล (dll / so หรือเรียกใช้งานได้) มาตรฐาน C ++ กำหนดให้สิ่งเหล่านี้มีการเชื่อมโยงภายในซึ่งหมายความว่าพวกเขาไม่สามารถมองเห็นได้ภายนอกหน่วยการแปล (ซึ่งจะกลายเป็นอ็อบเจ็กต์ไฟล์) ที่กำหนดไว้ ดังนั้นสิ่งนี้จึงช่วยแก้ปัญหานั้นได้
จุดที่ซับซ้อนคือเมื่อคุณมีextern
ตัวแปรส่วนกลาง ที่นี่ระบบที่เหมือน Windows และ Unix นั้นแตกต่างกันอย่างสิ้นเชิง
ในกรณีของ Windows (.exe และ. dll) extern
ตัวแปรส่วนกลางไม่ได้เป็นส่วนหนึ่งของสัญลักษณ์ที่ส่งออก กล่าวอีกนัยหนึ่งโมดูลที่แตกต่างกันจะไม่ทราบถึงตัวแปรส่วนกลางที่กำหนดไว้ในโมดูลอื่น ๆ ซึ่งหมายความว่าคุณจะได้รับข้อผิดพลาดของตัวเชื่อมโยงหากคุณลองสร้างไฟล์ปฏิบัติการที่ควรจะใช้extern
ตัวแปรที่กำหนดไว้ใน DLL เนื่องจากไม่ได้รับอนุญาต คุณจะต้องจัดเตรียมไฟล์อ็อบเจ็กต์ (หรือไลบรารีแบบคงที่) พร้อมคำจำกัดความของตัวแปรภายนอกนั้นและเชื่อมโยงแบบคงที่กับทั้งไฟล์ปฏิบัติการและ DLL ส่งผลให้มีตัวแปรส่วนกลางที่แตกต่างกันสองตัวแปร (ตัวหนึ่งเป็นของไฟล์ปฏิบัติการและอีกตัวที่เป็นของ DLL )
ในการส่งออกตัวแปรส่วนกลางใน Windows คุณต้องใช้ไวยากรณ์ที่คล้ายกับไวยากรณ์การส่งออก / นำเข้าของฟังก์ชันกล่าวคือ:
#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;
เมื่อคุณทำเช่นนั้นตัวแปรส่วนกลางจะถูกเพิ่มลงในรายการสัญลักษณ์ที่ส่งออกและสามารถเชื่อมโยงเหมือนกับฟังก์ชันอื่น ๆ ทั้งหมด
ในกรณีของสภาพแวดล้อมแบบ Unix (เช่น Linux) ไลบรารีแบบไดนามิกที่เรียกว่า "วัตถุที่ใช้ร่วมกัน" ที่มีส่วนขยายจะ.so
ส่งออกextern
ตัวแปรส่วนกลางทั้งหมด(หรือฟังก์ชัน) ในกรณีนี้หากคุณทำการเชื่อมโยงเวลาโหลดจากที่ใดก็ได้ไปยังไฟล์อ็อบเจ็กต์ที่แชร์ตัวแปรส่วนกลางจะถูกแชร์เช่นลิงก์เข้าด้วยกันเป็นหนึ่งเดียว โดยทั่วไประบบที่เหมือน Unix ได้รับการออกแบบมาเพื่อให้แทบไม่มีความแตกต่างระหว่างการเชื่อมโยงกับไลบรารีแบบคงที่หรือไดนามิก อีกครั้ง ODR ใช้ทั่วทั้งบอร์ด: extern
ตัวแปรส่วนกลางจะถูกแชร์ข้ามโมดูลซึ่งหมายความว่าควรมีคำจำกัดความเพียงคำเดียวสำหรับโมดูลทั้งหมดที่โหลด
ในที่สุดทั้งสองกรณีสำหรับ Windows หรือ Unix เหมือนระบบที่คุณสามารถทำเวลาทำงานเชื่อมโยงห้องสมุดแบบไดนามิกคือใช้ทั้งLoadLibrary()
/ GetProcAddress()
/ FreeLibrary()
หรือdlopen()
/ /dlsym()
dlclose()
ในกรณีนี้คุณต้องรับตัวชี้ไปยังสัญลักษณ์แต่ละตัวที่คุณต้องการใช้ด้วยตนเองและรวมถึงตัวแปรส่วนกลางที่คุณต้องการใช้ด้วย สำหรับตัวแปรส่วนกลางคุณสามารถใช้GetProcAddress()
หรือdlsym()
เช่นเดียวกับที่คุณทำสำหรับฟังก์ชันโดยที่ตัวแปรส่วนกลางเป็นส่วนหนึ่งของรายการสัญลักษณ์ที่ส่งออก (ตามกฎของย่อหน้าก่อนหน้า)
และแน่นอนว่าเป็นบันทึกสุดท้ายที่จำเป็น: ตัวแปรทั่วโลกควรจะหลีกเลี่ยง และฉันเชื่อว่าข้อความที่คุณยกมา (เกี่ยวกับสิ่งที่ "ไม่ชัดเจน") นั้นอ้างอิงถึงความแตกต่างเฉพาะแพลตฟอร์มที่ฉันเพิ่งอธิบายไป (ไลบรารีแบบไดนามิกไม่ได้กำหนดโดยมาตรฐาน C ++ จริงๆนี่คือพื้นที่เฉพาะแพลตฟอร์มซึ่งหมายความว่า มีความน่าเชื่อถือ / พกพาน้อยกว่ามาก)