ก่อนหน้านี้ฉันใช้สหภาพอย่างสะดวกสบาย วันนี้ฉันตื่นตระหนกเมื่อฉันอ่านโพสต์นี้และรู้ว่ารหัสนี้
union ARGB
{
uint32_t colour;
struct componentsTag
{
uint8_t b;
uint8_t g;
uint8_t r;
uint8_t a;
} components;
} pixel;
pixel.colour = 0xff040201; // ARGB::colour is the active member from now on
// somewhere down the line, without any edit to pixel
if(pixel.components.a) // accessing the non-active member ARGB::components
เป็นพฤติกรรมที่ไม่ได้กำหนดจริง ๆ แล้วคือการอ่านจากสมาชิกของสหภาพอื่นนอกเหนือจากที่เพิ่งเขียนถึงพฤติกรรมที่ไม่ได้กำหนด หากนี่ไม่ใช่การใช้งานของสหภาพแรงงานที่ตั้งใจไว้คืออะไร ใครช่วยอธิบายหน่อยได้ไหม?
ปรับปรุง:
ฉันต้องการชี้แจงบางสิ่งในความเข้าใจย้อนหลัง
- คำตอบสำหรับคำถามนั้นไม่เหมือนกันสำหรับ C และ C ++; น้องตัวน้อยที่ไม่รู้ของฉันติดแท็กเป็นทั้ง C และ C ++
- หลังจากกำจัดสิ่งสกปรกด้วยมาตรฐานของ C ++ 11 ฉันไม่สามารถสรุปได้อย่างชัดเจนว่ามันเรียกร้องการเข้าถึง / ตรวจสอบสมาชิกสหภาพที่ไม่ได้ทำงานอยู่นั้นไม่ได้กำหนดไว้ ทั้งหมดที่ฉันสามารถหาได้คือ§9.5 / 1:
หากการรวมแบบเลย์เอาต์มาตรฐานมีโครงสร้างเลย์เอาต์มาตรฐานหลายตัวที่ใช้ร่วมกันเริ่มต้นร่วมกันและหากวัตถุประเภทยูเนี่ยนแบบเลย์เอาต์มาตรฐานนี้มีหนึ่งในโครงสร้างแบบเลย์เอาท์แบบมาตรฐานจะอนุญาตให้ตรวจสอบลำดับเริ่มต้นทั่วไปของ ของสมาชิกโครงสร้าง layout แบบมาตรฐาน §9.2 / 19: โครงสร้างเลย์เอาต์มาตรฐานสองรายการใช้ลำดับเริ่มต้นร่วมกันหากสมาชิกที่เกี่ยวข้องมีประเภทที่เข้ากันได้กับโครงร่างและสมาชิกทั้งสองไม่เป็นบิตฟิลด์หรือทั้งสองเป็นบิตฟิลด์ที่มีความกว้างเท่ากันสำหรับลำดับแรกหรือมากกว่า สมาชิก.
- ในขณะที่อยู่ใน C ( C99 TC3 - DR 283เป็นต้นไป) มันถูกกฎหมายที่จะทำเช่นนั้น ( ขอบคุณ Pascal Cuoq ที่นำสิ่งนี้ขึ้นมา) อย่างไรก็ตามการพยายามทำมันยังสามารถนำไปสู่พฤติกรรมที่ไม่ได้กำหนดหากค่าการอ่านเกิดขึ้นไม่ถูกต้อง (เรียกว่า "การแทนแทร็บ") สำหรับประเภทที่อ่านได้ มิฉะนั้นการอ่านค่าคือการใช้งานที่กำหนดไว้
C89 / 90 เรียกสิ่งนี้ภายใต้พฤติกรรมที่ไม่ระบุ (ภาคผนวก J) และหนังสือของ K & R กล่าวว่ามันถูกกำหนดไว้แล้ว อ้างอิงจาก K&R:
นี่คือจุดประสงค์ของการรวมกัน - ตัวแปรเดียวที่สามารถถือเป็นหนึ่งในหลาย ๆ ประเภทที่ถูกกฎหมาย [... ] ตราบเท่าที่การใช้งานสอดคล้องกัน: ประเภทที่ดึงมาจะต้องเป็นประเภทที่จัดเก็บล่าสุด มันเป็นความรับผิดชอบของโปรแกรมเมอร์ที่จะต้องติดตามว่ามีการจัดเก็บประเภทใดในสหภาพ ผลลัพธ์ขึ้นอยู่กับการนำไปใช้งานหากบางสิ่งถูกจัดเก็บเป็นประเภทเดียวและแยกออกมาเป็นอีกประเภทหนึ่ง
สารสกัดจาก TC ++ PL ของ Stroustrup (เหมืองที่เน้น)
การใช้สหภาพอาจเป็นสิ่งจำเป็นสำหรับความเข้ากันได้ของข้อมูลบางครั้งใช้ในทางที่ผิดสำหรับ "การแปลงแบบ "
เหนือสิ่งอื่นใดคำถามนี้ (ที่ชื่อยังคงไม่เปลี่ยนแปลงเนื่องจากการถามของฉัน) ถูกวางด้วยความตั้งใจในการทำความเข้าใจวัตถุประสงค์ของสหภาพและไม่ใช่สิ่งที่มาตรฐานอนุญาตให้เช่นการใช้การสืบทอดสำหรับการใช้รหัสซ้ำคือแน่นอนอนุญาตโดยมาตรฐาน C ++ มันก็ไม่ได้มีจุดประสงค์หรือความตั้งใจเดิมของการแนะนำมรดกเป็นคุณลักษณะภาษา C ++ นี่คือเหตุผลที่คำตอบของ Andrey ยังคงเป็นคำตอบที่ได้รับการยอมรับ
scouring C++11's standard I couldn't conclusively say that it calls out accessing/inspecting a non-active union member is undefined [...] All I could find was §9.5/1
...จริงๆ? คุณอ้างถึงบันทึกย่อข้อยกเว้นไม่ใช่จุดหลักที่จุดเริ่มต้นของย่อหน้า : "ในสหภาพสมาชิกส่วนใหญ่ของข้อมูลที่ไม่คงที่สามารถใช้งานได้ตลอดเวลานั่นคือมูลค่าสูงสุดของ สมาชิกข้อมูลที่ไม่คงที่สามารถจัดเก็บในสหภาพได้ตลอดเวลา " - และลงไปที่ p4: "โดยทั่วไปเราต้องใช้การโทร destructor อย่างชัดเจนและกำหนดตำแหน่งโอเปอเรเตอร์ใหม่เพื่อเปลี่ยนสมาชิกที่ใช้งานอยู่ของสหภาพ "
b, g, r,
และอาจจะไม่ต่อเนื่องกันจึงไม่ตรงกับรูปแบบของการa
uint32_t
นี่คือนอกเหนือจากปัญหา Endianess ที่คนอื่นได้ชี้ให้เห็น