คอมไพเลอร์ได้รับอนุญาตให้ระเหยสารในท้องถิ่นได้หรือไม่?


25

พิจารณารหัสง่าย ๆ นี้:

void g();

void foo()
{
    volatile bool x = false;
    if (x)
        g();
}

https://godbolt.org/z/I2kBY7

คุณจะเห็นว่าค่าgccมิได้เพิ่มประสิทธิภาพการโทรมีศักยภาพในการclang gสิ่งนี้ถูกต้องในความเข้าใจของฉัน: เครื่องนามธรรมคือการสันนิษฐานว่าvolatileตัวแปรอาจเปลี่ยนแปลงได้ตลอดเวลา (เนื่องจากเป็นเช่นการแมปฮาร์ดแวร์) ดังนั้นการfalseเริ่มต้นการพับการifตรวจสอบอย่างต่อเนื่องจะผิด

แต่ MSVC กำจัดการเรียกไปที่gทั้งหมด (ทำให้การอ่านและเขียนไปยังvolatileแม้ว่า!) พฤติกรรมนี้เป็นไปตามมาตรฐานหรือไม่


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


การแก้ไข:

  • การกำจัดของการอ่านและการเขียนvolatileถูกกล่าวถึงที่นี่: มันอนุญาตให้คอมไพเลอร์เพื่อปรับให้เหมาะสมกับตัวแปรที่ระเหยได้หรือไม่? (ขอบคุณนาธาน!) ฉันคิดว่ามาตรฐานมีความชัดเจนอย่างมากที่ผู้อ่านและเขียนจะต้องเกิดขึ้น แต่การสนทนานั้นไม่ครอบคลุมว่าจะเป็นการถูกกฎหมายหรือไม่ที่คอมไพเลอร์จะใช้ผลลัพธ์ของการอ่านเพื่อการอนุญาตและการปรับให้เหมาะสมตามนั้น ฉันคิดว่านี่เป็น- / ไม่ได้ระบุในมาตรฐาน แต่ฉันจะมีความสุขถ้ามีคนพิสูจน์ฉันผิด

  • แน่นอนฉันสามารถสร้างxตัวแปรที่ไม่ใช่ในท้องถิ่นเพื่อแก้ไขปัญหาได้ คำถามนี้หมดไปจากความอยากรู้


3
นี่ดูเหมือนข้อผิดพลาดของคอมไพเลอร์ที่ชัดเจนสำหรับฉัน
Sam Varshavchik

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

3
แต่ฉันคิดว่าอาร์กิวเมนต์ของ OP ว่าตัวแก้ไขอาจถูกแก้ไขโดยดีบักเกอร์นั้นสมเหตุสมผล อาจมีบางคนควรยื่นรายงานข้อผิดพลาดด้วย MSVC
Brian

2
@curtguy แม้ว่าคุณจะทิ้งผลลัพธ์และ / หรือสมมติว่ามีค่าที่แน่นอนคุณยังคงอ่านมัน
Deduplicator

2
ที่น่าสนใจคือมันทำสำหรับ x64 เท่านั้น รุ่น x86 ยังคงเรียก g () godbolt.org/z/nc3Y-f
Jerry Jeremiah

คำตอบ:


2

ฉันคิดว่า [คำแนะนำในการดำเนินการ] (จำนวนย่อหน้าแตกต่างกัน) สามารถนำมาใช้เพื่ออธิบายพฤติกรรมของ MSVC:

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

มาตรฐานไม่อนุญาตให้มีการกำจัดของการอ่านผ่าน glvalue ผันผวน falseแต่ย่อหน้าข้างต้นอาจจะตีความได้ว่าช่วยให้การคาดการณ์ค่า


BTW มาตรฐาน C (N1570 6.2.4 / 2) บอกว่า

วัตถุมีอยู่มีที่อยู่คงที่และเก็บค่าที่เก็บไว้ล่าสุดตลอดอายุการใช้งาน 34


34) ในกรณีของวัตถุระเหยร้านสุดท้ายไม่จำเป็นต้องชัดเจนในโปรแกรม

มันไม่ชัดเจนว่าอาจมีร้านค้าที่ไม่ชัดเจนในวัตถุที่มีระยะเวลาการจัดเก็บอัตโนมัติในหน่วยความจำ C / รูปแบบวัตถุ


ยอมรับว่าคอมไพเลอร์อาจทราบเมื่อร้านค้าที่ไม่ชัดเจนเป็นไปได้บนแพลตฟอร์มเป้าหมาย
MM

1
ดังนั้นถ้าสิ่งนี้เป็นจริงแล้ววัตถุที่ระเหยได้ในท้องถิ่นนั้น (อย่างน้อยใน MSVC) ไม่มีจุดหมายอย่างสิ้นเชิง? มีสิ่งใดบ้างที่เพิ่มการvolatileซื้อให้คุณ (นอกเหนือจากการอ่าน / เขียนฟุ่มเฟือย) หากมันถูกละเว้นเพื่อจุดประสงค์ในการปรับให้เหมาะสมที่สุด?
Max Langhof

1
@ MaxLanghof มีความแตกต่างระหว่างไม่มีจุดหมายอย่างสิ้นเชิงและไม่มีผลค่อนข้างที่คุณต้องการ / คาดหวัง
Deduplicator

1
@MaxLanghof ผลลัพธ์ระดับกลางของการคำนวณจุดลอยตัวบางครั้งได้รับการเลื่อนขั้นเพื่อลงทะเบียน 80 บิตทำให้เกิดปัญหาความแม่นยำ ฉันเชื่อว่านี่เป็น gcc-ism และสามารถหลีกเลี่ยงได้โดยการประกาศคู่ผสมทั้งหมดเป็นความผันผวน ดู: gcc.gnu.org/bugzilla/show_bug.cgi?id=323
ForeverLearning

1
@philipxy PS ดูคำตอบของฉันฉันรู้ว่าการเข้าถึงนั้นถูกกำหนดตามการนำไปใช้ คำถามไม่เกี่ยวกับการเข้าถึง (การเข้าถึงวัตถุ) แต่การคาดการณ์ของค่า
นักกฎหมายด้านภาษา

2

TL; DRคอมไพเลอร์สามารถทำสิ่งที่มันต้องการในการเข้าถึงแบบระเหย แต่เอกสารนั้นต้องบอกคุณ - "ความหมายของการเข้าถึงผ่าน glvalue ที่ระเหยได้นั้นถูกกำหนดโดยการนำไปปฏิบัติ"


มาตรฐานกำหนดไว้สำหรับโปรแกรมที่อนุญาตให้ใช้ลำดับของ "การเข้าถึงแบบเปลี่ยนแปลงได้" และอื่น ๆ "พฤติกรรมที่สังเกตได้" (ทำได้โดย "ผลข้างเคียง") ที่การดำเนินการต้องปฏิบัติตาม "กฎ 'ตามที่'

แต่มาตรฐานบอกว่า (เน้นตัวหนาของฉัน):

Working Draft, มาตรฐานสำหรับการเขียนโปรแกรมภาษา C ++
หมายเลขเอกสาร: N4659
วันที่: 2017-03-21

§ 10.1.7.1 ตัวระบุ CV

5 ซีแมนทิกส์ของการเข้าถึงผ่าน glvalue ที่ระเหยได้นั้นถูกกำหนดโดยการนำไปปฏิบัติ [ ... ]

ในทำนองเดียวกันสำหรับอุปกรณ์แบบโต้ตอบ (เน้นตัวหนาของฉัน):

§ 4.6 การทำงานของโปรแกรม

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

7 ความต้องการขั้นต่ำในการนำไปปฏิบัติให้สอดคล้องคือ:

(7.1) - การเข้าถึงผ่าน glvalues ​​ระเหยได้รับการประเมินอย่างเคร่งครัดตามกฎของเครื่องนามธรรม
(7.2) - เมื่อสิ้นสุดโปรแกรมข้อมูลทั้งหมดที่เขียนลงในไฟล์จะต้องเหมือนกับผลลัพธ์ที่เป็นไปได้อย่างใดอย่างหนึ่งซึ่งการดำเนินการของโปรแกรมตามความหมายเชิงนามธรรมจะเกิดขึ้น
(7.3) - การเปลี่ยนแปลงอินพุทและเอาท์พุทของอุปกรณ์แบบอินเทอร์แอคทีฟจะเกิดขึ้นในลักษณะที่การส่งเอาต์พุตพร้อมท์จะถูกส่งจริงก่อนที่โปรแกรมจะรออินพุต สิ่งที่ถือว่าเป็นอุปกรณ์แบบโต้ตอบจะถูกกำหนดใช้งาน

สิ่งเหล่านี้เรียกรวมกันว่าพฤติกรรมที่สังเกตได้ของโปรแกรม [ ... ]

(อย่างไรก็ตามรหัสเฉพาะที่สร้างขึ้นสำหรับโปรแกรมไม่ได้ระบุไว้โดยมาตรฐาน)

ดังนั้นแม้ว่ามาตรฐานจะบอกว่าการเข้าถึงแบบระเหยไม่สามารถถูกตัดออกจากลำดับนามธรรมของผลข้างเคียงของเครื่องนามธรรม & พฤติกรรมที่สังเกตได้ซึ่งโค้ดบางอย่าง (อาจ) กำหนดไว้ แต่คุณไม่สามารถคาดหวังอะไรที่จะสะท้อนออกมาในรหัสวัตถุหรือโลกแห่งความจริง พฤติกรรมนอกเสียจากเอกสารรวบรวมของคุณจะบอกคุณว่าการเข้าถึงแบบใด เหมือนกันสำหรับอุปกรณ์แบบโต้ตอบ

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

คนเรื้อรังเชื่อว่าการเข้าถึงเครื่องระเหยแบบนามธรรมประเมิน / อ่านทำให้การอ่านและการกำหนดเครื่อง / เขียนนามธรรมทำให้การเขียนถูกนำไปใช้ ไม่มีพื้นฐานสำหรับความเชื่อนี้หากไม่มีเอกสารการปฏิบัติตามที่กล่าวไว้ เมื่อ / iff การนำไปใช้บอกว่าจริง ๆ แล้วมันทำอะไรบางอย่างกับ "การเข้าถึงแบบระเหย" ผู้คนจะได้รับความชอบธรรมในการคาดหวังสิ่งนั้น - อาจจะเป็นการสร้างรหัสวัตถุบางอย่าง


1
ผมหมายถึงนี้เดือดลงไป"ถ้าฉันมากับเครื่องที่ทุกผลข้างเคียงที่กล่าวถึงเป็นไม่มี Ops แล้วฉันมีกฎหมาย c ++ ดำเนินการโดยการรวบรวมทุกโปรแกรมจะไม่มี-op เป็น" แน่นอนว่าเรามีความสนใจในผลกระทบที่สังเกตได้จริงเนื่องจากผลข้างเคียงของเครื่องนามธรรมเป็นนามธรรมที่มีความซ้ำซ้อน สิ่งนี้ต้องการแนวคิดพื้นฐานของผลข้างเคียงและฉันจะให้เหตุผลว่า "การเข้าถึงแบบระเหยนำไปสู่คำแนะนำการเข้าถึงหน่วยความจำอย่างชัดเจน" เป็นส่วนหนึ่งของสิ่งนั้น (แม้ว่ามาตรฐานจะไม่สนใจ) ดังนั้นฉันจึงไม่ซื้อ " ถ้าคุณต้องการรหัสแทนความหมายเชิงนามธรรม " ถึงกระนั้น +1
Max Langhof

ใช่คุณภาพของการใช้งานมีความเกี่ยวข้อง อย่างไรก็ตามนอกเหนือจากการเขียนไปยังไฟล์ "observables" [sic] นั้นถูกนำไปใช้งาน หากคุณต้องการที่จะสามารถจุดพักชุดเข้าถึงหน่วยความจำที่เกิดขึ้นจริงบางอย่างมี 'ผันผวน' ละเว้น ฯลฯ ในนามธรรมระเหยอ่านและเขียนแล้วคุณต้องได้รับนักเขียนคอมไพเลอร์ของคุณเพื่อการส่งออกรหัสที่เหมาะสม PS ใน C ++ "ผลข้างเคียง" ไม่ได้ใช้สำหรับการสังเกตพฤติกรรมต่อ se มันใช้สำหรับการอธิบายการประเมินลำดับบางส่วนของนิพจน์ย่อย
philipxy

สนใจอธิบาย [sic] ไหม? คุณอ้างแหล่งที่มาใดและเกิดข้อผิดพลาดอะไร
Max Langhof

จริง ๆ แล้วฉันแค่หมายความว่าเครื่องนามธรรมที่สังเกตได้เป็นเพียงในโลกแห่งความเป็นจริงที่สังเกตได้ถ้า & วิธีการใช้งานบอกว่ามันเป็น
philipxy

1
คุณกำลังบอกว่าการติดตั้งใช้งานสามารถอ้างได้ว่าไม่มีสิ่งใดเป็นอุปกรณ์แบบอินเทอร์แอคทีฟดังนั้นโปรแกรมใดสามารถทำอะไรได้บ้างและมันจะยังคงถูกต้องอยู่ใช่ไหม? (หมายเหตุ: ผมไม่เข้าใจความสำคัญของคุณบนอุปกรณ์แบบโต้ตอบ.)
curiousguy

-1

ฉันเชื่อว่าเป็นการผิดกฎหมายที่จะข้ามการตรวจสอบ

ย่อหน้าที่ทุกคนชอบที่จะพูด

34) ในกรณีของวัตถุระเหยร้านสุดท้ายไม่จำเป็นต้องชัดเจนในโปรแกรม

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

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


คุณอธิบายได้ไหมว่าทำไมมันถึงชั่วร้าย ในการแสดงรหัสฟังก์ชันไม่สามารถถูกเรียกได้อย่างแท้จริง
David Schwartz

@DavidSchwartz คุณสามารถสรุปได้ว่าหลังจากที่คุณระบุความหมายของตัวแปรระเหยท้องถิ่น (ดูย่อหน้าที่ยกมาด้านบน) มาตรฐานตัวเองหมายเหตุที่volatileควรจะเป็นคำแนะนำการใช้งานที่คุ้มค่าสามารถเปลี่ยนแปลงได้โดยวิธีการที่ไม่รู้จักกับการดำเนินการ
Max Langhof

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

@DavidSchwartz แน่นอนมันสามารถ - โดยทำตามความหมาย (โดยเฉพาะอย่างยิ่งการอ่านและเขียน) ของเครื่องนามธรรม มันอาจไม่สามารถปรับให้เหมาะสมอย่างถูกต้อง - นั่นคือจุดมาตรฐาน ตอนนี้มันเป็นบันทึกและไม่เป็นบรรทัดฐานและอย่างที่เราทั้งคู่กล่าวว่าการนำไปปฏิบัติสามารถระบุสิ่งที่volatileทำและยึดติดกับสิ่งนั้น จุดของฉันคือรหัสตัวเอง (ตามเครื่อง C / มาตรฐาน / นามธรรม) ไม่อนุญาตให้คุณตรวจสอบว่าgสามารถเรียก
Max Langhof

@DavidSchwartz รหัสไม่แสดงอะไรอย่างนั้นเพราะไม่มีการเขียนโดยนัยไม่ปฏิบัติตามจากรหัส
n คำสรรพนาม 'm
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.