การเข้าถึงสมาชิกสหภาพที่ไม่ได้ใช้งานและพฤติกรรมที่ไม่ได้กำหนด?


129

ฉันรู้สึกว่าการเข้าถึงไฟล์ unionสมาชิกนอกเหนือจากชุดสุดท้ายคือ UB แต่ดูเหมือนว่าฉันจะไม่พบข้อมูลอ้างอิงที่มั่นคง (นอกเหนือจากคำตอบที่อ้างว่าเป็น UB แต่ไม่ได้รับการสนับสนุนจากมาตรฐาน)

ดังนั้นพฤติกรรมที่ไม่ได้กำหนดหรือไม่?


3
C99 (และฉันเชื่อว่า C ++ 11 เช่นกัน) อนุญาตให้พิมพ์ด้วยสหภาพแรงงานอย่างชัดเจน ดังนั้นฉันคิดว่ามันอยู่ภายใต้พฤติกรรม "กำหนดการนำไปใช้งาน"
ลึกลับ

1
ฉันใช้มันหลายครั้งเพื่อแปลงจาก int แต่ละรายการเป็น char ดังนั้นฉันรู้แน่นอนว่ามันไม่ได้ถูกกำหนดไว้ ฉันใช้มันกับคอมไพเลอร์ Sun CC ดังนั้นมันอาจยังคงขึ้นอยู่กับคอมไพเลอร์
go4sri

42
@ go4sri: เห็นได้ชัดว่าคุณไม่รู้ว่าพฤติกรรมที่ไม่ได้กำหนดหมายถึงอะไร ความจริงที่ดูเหมือนว่าจะได้ผลสำหรับคุณในบางกรณีไม่ได้ขัดแย้งกับความไม่ได้กำหนดของมัน
Benjamin Lindley


4
@Mysticial บล็อกโพสต์ที่คุณลิงก์เป็นข้อมูลเฉพาะเกี่ยวกับ C99 คำถามนี้ถูกแท็กเฉพาะสำหรับ C ++
davmac

คำตอบ:


131

ความสับสนคือ C อนุญาตให้มีการกดพิมพ์ผ่านยูเนี่ยนอย่างชัดเจนในขณะที่ C ++ () ไม่ได้รับอนุญาต

6.5.2.3 โครงสร้างและสมาชิกสหภาพแรงงาน

95) หากสมาชิกที่ใช้ในการอ่านเนื้อหาของอ็อบเจ็กต์ยูเนี่ยนไม่เหมือนกับสมาชิกล่าสุดที่ใช้ในการจัดเก็บค่าในอ็อบเจ็กต์ส่วนที่เหมาะสมของการแทนค่าอ็อบเจ็กต์จะถูกตีความใหม่เป็นการแสดงอ็อบเจ็กต์ในใหม่ พิมพ์ตามที่อธิบายไว้ใน 6.2.6 (กระบวนการบางครั้งเรียกว่า '' type punning '') นี่อาจเป็นการแสดงกับดัก

สถานการณ์กับ C ++:

9.5 สหภาพแรงงาน [class.union]

ในสหภาพสมาชิกข้อมูลที่ไม่คงที่ส่วนใหญ่สามารถใช้งานได้ตลอดเวลานั่นคือค่าของสมาชิกข้อมูลที่ไม่คงที่ส่วนใหญ่สามารถเก็บไว้ในสหภาพได้ตลอดเวลา

C ++ ต่อมามีภาษาที่อนุญาตให้ใช้สหภาพที่มีstructs ที่มีลำดับเริ่มต้นทั่วไป อย่างไรก็ตามสิ่งนี้ไม่อนุญาตให้มีการเจาะประเภท

เพื่อตรวจสอบว่าการเจาะแบบสหภาพคือได้รับอนุญาตใน C ++ เราจะต้องค้นหาต่อไป จำได้ว่า เป็นการอ้างอิงเชิงบรรทัดฐานสำหรับ C ++ 11 (และ C99 มีภาษาคล้ายกับ C11 ที่อนุญาตให้ใช้การพิมพ์ยูเนี่ยน):

3.9 ประเภท [basic.types]

4 - การแสดงวัตถุของวัตถุประเภท T คือลำดับของวัตถุถ่านที่ไม่ได้ลงนาม N ที่นำขึ้นโดยวัตถุประเภท T โดยที่ N เท่ากับขนาดของ (T) การแทนค่าของอ็อบเจ็กต์คือชุดของบิตที่เก็บค่าของชนิด T สำหรับประเภทที่สามารถคัดลอกได้เล็กน้อยการแทนค่าคือชุดของบิตในการแทนอ็อบเจ็กต์ที่กำหนดค่าซึ่งเป็นองค์ประกอบที่ไม่ต่อเนื่องของการนำไปใช้งาน - de fi ned ชุดของค่า 42
42) จุดประสงค์คือโมเดลหน่วยความจำของ C ++ เข้ากันได้กับ ISO / IEC 9899 ภาษาโปรแกรม C

มันน่าสนใจเป็นพิเศษเมื่อเราอ่าน

3.8 อายุการใช้งานวัตถุ [basic.life]

อายุการใช้งานของอ็อบเจ็กต์ประเภท T เริ่มต้นเมื่อ: - ได้รับการจัดเก็บที่มีการจัดตำแหน่งและขนาดที่เหมาะสมสำหรับประเภท T และ - ถ้าอ็อบเจ็กต์มีการกำหนดค่าเริ่มต้นที่ไม่สำคัญการกำหนดค่าเริ่มต้นจะเสร็จสมบูรณ์

ดังนั้นสำหรับประเภทดั้งเดิม (ซึ่งipso factoมีการเริ่มต้นเล็กน้อย) ที่มีอยู่ในการรวมกันอายุการใช้งานของวัตถุจะครอบคลุมอย่างน้อยอายุการใช้งานของสหภาพเอง สิ่งนี้ทำให้เราสามารถเรียกใช้

3.9.2 ประเภทของสารประกอบ [basic.compound]

หากออบเจ็กต์ประเภท T ตั้งอยู่ที่แอดเดรส A ตัวชี้ประเภท cv T * ที่มีค่าคือแอดเดรส A จะถูกบอกให้ชี้ไปที่อ็อบเจ็กต์นั้นโดยไม่คำนึงว่าจะได้รับค่าอย่างไร

สมมติว่าการดำเนินการที่เราสนใจคือ type-punning คือการรับค่าของสมาชิกสหภาพแรงงานที่ไม่ได้ใช้งานและตามที่ระบุไว้ข้างต้นว่าเรามีการอ้างอิงที่ถูกต้องไปยังวัตถุที่อ้างถึงโดยสมาชิกนั้นการดำเนินการนั้นมีค่าเท่ากับ - การแปลงค่า:

4.1 การแปลง Lvalue-to-rvalue [Conv.lval]

ค่า glvalue ของประเภท non-function และ non-array Tสามารถแปลงเป็น prvalue ได้ หากTเป็นประเภทที่ไม่สมบูรณ์โปรแกรมที่จำเป็นต้องมีการแปลงนี้จะมีรูปแบบไม่ถูกต้อง หากอ็อบเจ็กต์ที่ glvalue อ้างถึงไม่ใช่อ็อบเจ็กต์ประเภทTและไม่ใช่อ็อบเจ็กต์ประเภทที่มาจากTหรือถ้าอ็อบเจ็กต์ไม่ได้กำหนดค่าเริ่มต้นโปรแกรมที่จำเป็นต้องมีการแปลงนี้จะมีพฤติกรรมที่ไม่เหมาะสม

คำถามก็คือว่าวัตถุที่เป็นสมาชิกสหภาพที่ไม่ได้ใช้งานถูกเตรียมใช้งานโดยหน่วยเก็บข้อมูลไปยังสมาชิกสหภาพที่ใช้งานอยู่หรือไม่ เท่าที่ฉันสามารถบอกได้นี่ไม่ใช่กรณีและแม้ว่า:

  • ยูเนี่ยนถูกคัดลอกไปยังที่charเก็บอาร์เรย์และด้านหลัง (3.9: 2) หรือ
  • สหภาพถูกคัดลอกไปยังสหภาพอื่นที่เป็นประเภทเดียวกัน (3.9: 3) หรือ
  • ยูเนี่ยนถูกเข้าถึงข้ามขอบเขตภาษาโดยองค์ประกอบของโปรแกรมที่สอดคล้องกับ ISO / IEC 9899 (เท่าที่กำหนดไว้) (3.9: 4 หมายเหตุ 42) จากนั้น

การเข้าถึงสหภาพโดยสมาชิกที่ไม่ได้ใช้งานได้รับการกำหนดและถูกกำหนดให้เป็นไปตามวัตถุและการแทนค่าการเข้าถึงโดยไม่มีการแทรกกลางอย่างใดอย่างหนึ่งข้างต้นเป็นพฤติกรรมที่ไม่ได้กำหนดไว้ สิ่งนี้มีผลกระทบต่อการเพิ่มประสิทธิภาพที่อนุญาตให้ดำเนินการกับโปรแกรมดังกล่าวเนื่องจากการใช้งานอาจสันนิษฐานได้ว่าพฤติกรรมที่ไม่ได้กำหนดจะไม่เกิดขึ้น

นั่นคือแม้ว่าเราสามารถสร้างค่า lvalue ให้กับสมาชิกสหภาพแรงงานที่ไม่ได้ใช้งานได้อย่างถูกต้องตามกฎหมาย (ซึ่งเป็นเหตุผลว่าทำไมการมอบหมายให้กับสมาชิกที่ไม่ได้ใช้งานโดยไม่มีการก่อสร้างก็เป็นเรื่องปกติ) แต่ก็ถือว่าไม่ได้เริ่มต้น


5
3.8 / 1 กล่าวว่าอายุการใช้งานของวัตถุสิ้นสุดลงเมื่อมีการนำที่เก็บข้อมูลกลับมาใช้ นั่นบ่งบอกให้ฉันทราบว่าสมาชิกที่ไม่ได้ใช้งานตลอดอายุการใช้งานของสหภาพสิ้นสุดลงเนื่องจากพื้นที่เก็บข้อมูลถูกนำมาใช้ใหม่สำหรับสมาชิกที่ใช้งานอยู่ นั่นหมายความว่าคุณมีข้อ จำกัด ในการใช้งานสมาชิก (3.8 / 6)
bames53

2
ภายใต้การตีความนั้นหน่วยความจำทุกบิตพร้อมกันจะมีวัตถุทุกประเภทที่สามารถเริ่มต้นได้เล็กน้อยและมีการจัดตำแหน่งที่เหมาะสม ... ดังนั้นอายุการใช้งานของประเภทการเริ่มต้นที่ไม่สำคัญใด ๆ จะสิ้นสุดลงทันทีเนื่องจากที่เก็บข้อมูลจะถูกนำกลับมาใช้สำหรับประเภทอื่น ๆ ทั้งหมดเหล่านี้ ( และไม่รีสตาร์ทเนื่องจากไม่สามารถเริ่มต้นได้เล็กน้อย)?
bames53

3
ข้อความ 4.1 นั้นสมบูรณ์และขาดอย่างสมบูรณ์และได้มีการเขียนใหม่ มันไม่ได้รับอนุญาตทุกประเภทของสิ่งที่ถูกต้องสมบูรณ์: มันไม่ได้รับอนุญาตที่กำหนดเองmemcpyการใช้งาน (การเข้าถึงวัตถุที่ใช้unsigned charlvalues) ก็ไม่ได้รับอนุญาตเข้าถึง*pหลังจากint *p = 0; const int *const *pp = &p;(แม้ว่าการแปลงนัยจากint**การconst int*const*ที่ถูกต้อง) ก็ไม่ได้รับอนุญาตเข้าถึงแม้หลังจากที่c ปัญหา CWG 616 คำใหม่อนุญาตหรือไม่ นอกจากนี้ยังมี [basic.lval] struct S s; const S &c = s;

2
@Omnifarious: นั่นเป็นเรื่องที่สมเหตุสมผลแม้ว่าจะต้องชี้แจงด้วย (และมาตรฐาน C ยังต้องชี้แจงด้วย btw) ความ&หมายของตัวดำเนินการยูนารีหมายถึงเมื่อนำไปใช้กับสมาชิกสหภาพ ฉันคิดว่าตัวชี้ผลลัพธ์ควรจะใช้งานได้เพื่อเข้าถึงสมาชิกอย่างน้อยก็จนกว่าจะถึงครั้งต่อไปที่จะใช้ lvalue ของสมาชิกอื่นทั้งทางตรงและทางอ้อมในครั้งถัดไป แต่ใน gcc ตัวชี้ไม่สามารถใช้งานได้แม้จะนานขนาดนั้นซึ่งทำให้เกิดคำถามว่าอะไร ตัว&ดำเนินการควรจะหมายถึง
supercat

4
คำถามหนึ่งเกี่ยวกับ"จำได้ว่า c99 เป็นการอ้างอิงเชิงบรรทัดฐานสำหรับ C ++ 11"ไม่ได้มีความเกี่ยวข้องเพียงอย่างเดียวโดยที่มาตรฐาน c ++ อ้างถึงมาตรฐาน C อย่างชัดเจน (เช่นสำหรับฟังก์ชันไลบรารี c)
MikeMB

28

มาตรฐาน C ++ 11 บอกอย่างนี้

9.5 สหภาพแรงงาน

ในสหภาพสมาชิกข้อมูลที่ไม่คงที่ส่วนใหญ่สามารถใช้งานได้ตลอดเวลานั่นคือค่าของสมาชิกข้อมูลที่ไม่คงที่ส่วนใหญ่สามารถเก็บไว้ในสหภาพได้ตลอดเวลา

หากเก็บไว้เพียงค่าเดียวคุณจะอ่านค่าอื่นได้อย่างไร มันไม่ได้อยู่ที่นั่น


เอกสาร gcc แสดงรายการสิ่งนี้ภายใต้พฤติกรรมที่กำหนดการนำไปใช้งาน

  • สมาชิกของยูเนี่ยนอ็อบเจ็กต์ถูกเข้าถึงโดยใช้สมาชิกประเภทอื่น (C90 6.3.2.3)

ไบต์ที่เกี่ยวข้องของการเป็นตัวแทนของอ็อบเจ็กต์จะถือว่าเป็นอ็อบเจ็กต์ประเภทที่ใช้สำหรับการเข้าถึง โปรดดูที่ Type-punning นี่อาจเป็นการแสดงกับดัก

แสดงว่าสิ่งนี้ไม่จำเป็นสำหรับมาตรฐาน C


2016-01-05: จากความคิดเห็นฉันได้เชื่อมโยงกับC99 Defect Report # 283ซึ่งเพิ่มข้อความที่คล้ายกันเป็นเชิงอรรถในเอกสารมาตรฐาน C:

78a) หากสมาชิกที่ใช้ในการเข้าถึงเนื้อหาของอ็อบเจ็กต์ยูเนี่ยนไม่เหมือนกับสมาชิกล่าสุดที่ใช้ในการจัดเก็บค่าในอ็อบเจ็กต์ส่วนที่เหมาะสมของการแทนค่าอ็อบเจ็กต์จะถูกตีความอีกครั้งเป็นการแสดงอ็อบเจ็กต์ในใหม่ พิมพ์ตามที่อธิบายไว้ใน 6.2.6 (กระบวนการบางครั้งเรียกว่า "type punning") นี่อาจเป็นการแสดงกับดัก

ไม่แน่ใจว่าจะชี้แจงได้มากหรือไม่โดยพิจารณาว่าเชิงอรรถไม่ใช่บรรทัดฐานสำหรับมาตรฐาน


10
@LuchianGrigore: UB ไม่ใช่สิ่งที่มาตรฐานบอกว่าเป็น UB แต่เป็นสิ่งที่มาตรฐานไม่ได้อธิบายว่าควรทำงานอย่างไร นี่เป็นกรณีดังกล่าว มาตรฐานอธิบายถึงสิ่งที่เกิดขึ้นหรือไม่? มันบอกว่ามีการกำหนดการใช้งานหรือไม่? ไม่ใช่และไม่ มันก็คือ UB ยิ่งไปกว่านั้นเกี่ยวกับอาร์กิวเมนต์ "สมาชิกแชร์ที่อยู่หน่วยความจำเดียวกัน" คุณจะต้องอ้างถึงกฎการใช้นามแฝงซึ่งจะนำคุณไปที่ UB อีกครั้ง
Yakov Galka

5
@Luchian: ค่อนข้างชัดเจนว่าหมายถึงอะไร"นั่นคือค่าของสมาชิกข้อมูลที่ไม่คงที่ส่วนใหญ่สามารถจัดเก็บไว้ในสหภาพได้ตลอดเวลา"
Benjamin Lindley

5
@LuchianGrigore: มีค่ะ มีกรณีจำนวนไม่ จำกัด ที่มาตรฐานไม่ได้ (และไม่สามารถ) อยู่ได้ (C ++ เป็น VM ของทัวริงที่สมบูรณ์ดังนั้นจึงไม่สมบูรณ์) แล้วไงล่ะ? มันอธิบายว่า "ใช้งานอยู่" หมายความว่าอย่างไรอ้างอิงถึงคำพูดข้างต้นหลังจาก "นั่นคือ"
Yakov Galka

8
@LuchianGrigore: การละเว้นคำจำกัดความที่ชัดเจนของพฤติกรรมยังถือเป็นพฤติกรรมที่ไม่ได้กำหนดตามหัวข้อคำจำกัดความ
jxh

5
@Claudiu นั่นคือ UB ด้วยเหตุผลที่แตกต่าง - มันละเมิดนามแฝงที่เข้มงวด
อาถรรพ์

18

ฉันคิดว่ามาตรฐานที่ใกล้เคียงที่สุดคือการบอกว่าพฤติกรรมที่ไม่ได้กำหนดคือจุดที่กำหนดพฤติกรรมสำหรับสหภาพที่มีลำดับเริ่มต้นทั่วไป (C99, §6.5.2.3 / 5):

มีการรับประกันพิเศษอย่างหนึ่งเพื่อลดความซับซ้อนในการใช้สหภาพแรงงาน: หากสหภาพแรงงานมีโครงสร้างหลายอย่างที่ใช้ลำดับเริ่มต้นร่วมกัน (ดูด้านล่าง) และหากออบเจ็กต์ของสหภาพมีโครงสร้างเหล่านี้อยู่ในปัจจุบันจะได้รับอนุญาตให้ตรวจสอบทั่วไป ส่วนเริ่มต้นของส่วนใดก็ได้ที่สามารถมองเห็นการประกาศประเภทที่สมบูรณ์ของสหภาพได้ โครงสร้างสองโครงสร้างใช้ลำดับเริ่มต้นร่วมกันหากสมาชิกที่เกี่ยวข้องมีชนิดที่เข้ากันได้ (และสำหรับบิตฟิลด์มีความกว้างเท่ากัน) สำหรับลำดับของสมาชิกเริ่มต้นตั้งแต่หนึ่งตัวขึ้นไป

C ++ 11 ให้ข้อกำหนด / การอนุญาตที่คล้ายกันที่§9.2 / 19:

ถ้ายูเนี่ยนโครงร่างมาตรฐานมีโครงสร้างโครงร่างมาตรฐานสองชุดขึ้นไปที่แบ่งลำดับเริ่มต้นร่วมกันและถ้าออบเจ็กต์แบบร่วมโครงร่างมาตรฐานในปัจจุบันมีโครงสร้างโครงร่างมาตรฐานอย่างใดอย่างหนึ่งเหล่านี้จะได้รับอนุญาตให้ตรวจสอบส่วนเริ่มต้นทั่วไปของใด ๆ ของพวกเขา. โครงสร้างโครงร่างมาตรฐานสองรายการใช้ลำดับเริ่มต้นร่วมกันหากสมาชิกที่สอดคล้องกันมีชนิดที่เข้ากันได้กับโครงร่างและสมาชิกทั้งสองไม่มีฟิลด์บิตหรือทั้งสองเป็นฟิลด์บิตที่มีความกว้างเท่ากันสำหรับลำดับของสมาชิกเริ่มต้นตั้งแต่หนึ่งตัวขึ้นไป

แม้ว่าทั้งสองจะไม่ได้ระบุไว้โดยตรง แต่ทั้งสองก็มีนัยยะที่ชัดเจนว่า "การตรวจสอบ" (การอ่าน) สมาชิก "ได้รับอนุญาต" ก็ต่อเมื่อ 1) เป็น (ส่วนหนึ่งของ) สมาชิกที่เขียนล่าสุดหรือ 2) เป็นส่วนหนึ่งของการเริ่มต้นทั่วไป ลำดับ.

นั่นไม่ใช่คำสั่งโดยตรงว่าการทำอย่างอื่นเป็นพฤติกรรมที่ไม่ได้กำหนด แต่เป็นสิ่งที่ใกล้เคียงที่สุดที่ฉันทราบ


เพื่อให้เสร็จสมบูรณ์คุณต้องทราบว่า "ประเภทที่เข้ากันได้กับเค้าโครง" สำหรับ C ++ คืออะไรหรือ "ประเภทที่เข้ากันได้" สำหรับ C.
Michael Anderson

2
@ MichaelAnderson: ใช่และไม่ใช่ คุณต้องจัดการกับสิ่งเหล่านั้นเมื่อ / หากคุณต้องการแน่ใจว่ามีบางสิ่งอยู่ในข้อยกเว้นนี้หรือไม่ - แต่คำถามที่แท้จริงคือสิ่งที่ชัดเจนว่าอยู่นอกข้อยกเว้นนั้นให้ UB อย่างแท้จริงหรือไม่ ฉันคิดว่านั่นเป็นนัยที่ชัดเจนเพียงพอที่จะทำให้เจตนาชัดเจน แต่ฉันไม่คิดว่ามันจะระบุโดยตรง
Jerry Coffin

"ลำดับเริ่มต้นทั่วไป" นี้อาจบันทึกโครงการของฉันไว้ 2 หรือ 3 รายการจากถังเขียนซ้ำ ฉันรู้สึกสดใสเมื่อได้อ่านครั้งแรกเกี่ยวกับการใช้การลงโทษส่วนใหญ่unionที่ไม่ได้กำหนดไว้เนื่องจากฉันได้รับความประทับใจจากบล็อกหนึ่ง ๆ ว่าสิ่งนี้ใช้ได้และได้สร้างโครงสร้างและโครงการขนาดใหญ่หลายโครงการไว้รอบ ๆ ตอนนี้ฉันคิดว่าฉันอาจจะโอเคเพราะฉันunionมีคลาสที่มีประเภทเดียวกันอยู่ด้านหน้า
underscore_d

@JerryCoffin ฉันคิดว่าคุณกำลังบอกใบ้คำถามเดียวกันกับฉัน: จะเกิดอะไรขึ้นถ้าของเราunionมีเช่น a uint8_tและ a class Something { uint8_t myByte; [...] };- ฉันจะถือว่าเงื่อนไขนี้จะใช้ที่นี่ด้วย แต่มันตั้งใจมากที่จะอนุญาตเฉพาะstructs โชคดีที่ฉันใช้สิ่งเหล่านี้แทนการใช้แบบดั้งเดิมอยู่แล้ว: O
underscore_d

@underscore_d: มาตรฐาน C อย่างน้อยก็ครอบคลุมคำถามนั้น: "ตัวชี้ไปยังออบเจ็กต์โครงสร้างที่ถูกแปลงอย่างเหมาะสมชี้ไปที่สมาชิกเริ่มต้น (หรือถ้าสมาชิกนั้นเป็นบิตฟิลด์จากนั้นไปยังหน่วยที่มันอยู่) , และในทางกลับกัน."
Jerry Coffin

12

คำตอบที่ยังไม่ได้กล่าวถึงคือเชิงอรรถ 37 ในย่อหน้า 21 ของหัวข้อ 6.2.5:

โปรดสังเกตว่าชนิดการรวมไม่รวมประเภทการรวมเนื่องจากวัตถุที่มีประเภทการรวมกันสามารถมีสมาชิกได้ครั้งละหนึ่งคนเท่านั้น

ข้อกำหนดนี้ดูเหมือนจะบอกเป็นนัยอย่างชัดเจนว่าคุณต้องไม่เขียนในสมาชิกและอ่านอีกข้อหนึ่ง ในกรณีนี้อาจเป็นพฤติกรรมที่ไม่ได้กำหนดโดยขาดข้อมูลจำเพาะ


การใช้งานจำนวนมากบันทึกรูปแบบการจัดเก็บและกฎโครงร่าง ข้อกำหนดดังกล่าวในหลาย ๆ กรณีจะบ่งบอกถึงผลกระทบของการอ่านที่เก็บข้อมูลประเภทหนึ่งและการเขียนอีกประเภทหนึ่งจะเป็นอย่างไรหากไม่มีกฎที่บอกว่าคอมไพเลอร์ไม่จำเป็นต้องใช้รูปแบบการจัดเก็บที่กำหนดไว้จริง ๆ ยกเว้นเมื่อมีการอ่านและเขียนสิ่งต่างๆโดยใช้พอยน์เตอร์ ประเภทอักขระ
supercat

-3

ฉันอธิบายเรื่องนี้ด้วยตัวอย่าง
สมมติว่าเรามีสหภาพดังต่อไปนี้:

union A{
   int x;
   short y[2];
};

ผมคิดว่ามันsizeof(int)ให้ 4 และนั่นsizeof(short)ให้ 2.
เมื่อคุณเขียนunion A a = {10}มันให้สร้างประเภท A ใหม่ใส่ค่า 10

ความทรงจำของคุณควรมีลักษณะเช่นนั้น: (โปรดจำไว้ว่าสมาชิกสหภาพแรงงานทั้งหมดได้รับตำแหน่งเดียวกัน)

       | x |
       | y [0] | y [1] |
       -----------------------------------------
   a-> | 0000 0000 | 0000 0000 | 0000 0000 | 0000 1010 |
       -----------------------------------------

อย่างที่คุณเห็นค่าของ ax คือ 10 ค่าของ ay 1คือ 10 และค่าของ ay [0] คือ 0

ตอนนี้จะเกิดอะไรขึ้นถ้าฉันทำสิ่งนี้?

a.y[0] = 37;

หน่วยความจำของเราจะมีลักษณะดังนี้:

       | x |
       | y [0] | y [1] |
       -----------------------------------------
   a-> | 0000 0000 | 0010 0101 | 0000 0000 | 0000 1010 |
       -----------------------------------------

สิ่งนี้จะเปลี่ยนค่าของ ax เป็น 2424842 (เป็นทศนิยม)

ตอนนี้ถ้าสหภาพของคุณมีการลอยตัวหรือสองเท่าแผนที่หน่วยความจำของคุณจะยุ่งเหยิงมากขึ้นเนื่องจากวิธีการจัดเก็บตัวเลขที่แน่นอน ข้อมูลเพิ่มเติมที่คุณสามารถได้รับในที่นี่


18
:) นี่ไม่ใช่สิ่งที่ฉันถาม ฉันรู้ว่าเกิดอะไรขึ้นภายใน ฉันรู้ว่ามันได้ผล ถามว่าอยู่ในเกณฑ์มาตรฐานไหม
Luchian Grigore
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.