คำตอบด้านบนคือความเข้าใจผิดที่ผิด (แต่เป็นเรื่องธรรมดา):
พฤติกรรมที่ไม่ได้กำหนดเป็นคุณสมบัติรันไทม์ * มันCAN NOT "เวลาเดินทาง"!
การดำเนินการบางอย่างถูกกำหนด (ตามมาตรฐาน) เพื่อให้มีผลข้างเคียงและไม่สามารถปรับให้เหมาะสมได้ การดำเนินการที่ทำ I / O หรือที่เข้าถึงvolatile
ตัวแปรจัดอยู่ในประเภทนี้
อย่างไรก็ตามมีข้อแม้: UB อาจเป็นพฤติกรรมใด ๆรวมถึงพฤติกรรมที่ยกเลิกการดำเนินการก่อนหน้านี้ ซึ่งอาจส่งผลที่คล้ายกันในบางกรณีกับการเพิ่มประสิทธิภาพโค้ดก่อนหน้านี้
ในความเป็นจริงสิ่งนี้สอดคล้องกับคำพูดในคำตอบด้านบน (เน้นของฉัน):
การดำเนินการที่สอดคล้องกันซึ่งเรียกใช้โปรแกรมที่มีรูปแบบที่ดีจะทำให้เกิดพฤติกรรมที่สังเกตได้เช่นเดียวกับหนึ่งในการดำเนินการที่เป็นไปได้ของอินสแตนซ์ที่เกี่ยวข้องของเครื่องนามธรรมที่มีโปรแกรมเดียวกันและอินพุตเดียวกัน
อย่างไรก็ตามหากการดำเนินการดังกล่าวมีการดำเนินการที่ไม่ได้กำหนดมาตรฐานสากลฉบับนี้ไม่ได้กำหนดข้อกำหนดใด ๆ เกี่ยวกับการดำเนินการตามโปรแกรมนั้นด้วยข้อมูลที่ป้อนเข้านั้น
ใช่คำพูดนี้กล่าวว่า"ไม่ได้เกี่ยวกับการดำเนินการก่อนการดำเนินการที่ไม่ได้กำหนดครั้งแรก"แต่โปรดสังเกตว่านี่เป็นเรื่องเกี่ยวกับโค้ดที่กำลังดำเนินการโดยเฉพาะไม่ใช่เพียงการรวบรวม
ท้ายที่สุดพฤติกรรมที่ไม่ได้กำหนดที่ไม่สามารถเข้าถึงได้จริงจะไม่ทำอะไรเลยและสำหรับบรรทัดที่มี UB ที่จะถึงจริงรหัสที่นำหน้าจะต้องดำเนินการก่อน!
ใช่เมื่อดำเนินการ UBผลกระทบใด ๆ ของการดำเนินการก่อนหน้านี้จะไม่ถูกกำหนด แต่จนกว่าจะเป็นเช่นนั้นการทำงานของโปรแกรมจะถูกกำหนดไว้อย่างดี
อย่างไรก็ตามโปรดทราบว่าการดำเนินการทั้งหมดของโปรแกรมที่ทำให้เกิดเหตุการณ์นี้สามารถปรับให้เหมาะสมกับโปรแกรมที่เทียบเท่ารวมถึงโปรแกรมใด ๆ ที่ดำเนินการก่อนหน้านี้ แต่ยกเลิกการทำงานของเอฟเฟกต์ ดังนั้นรหัสก่อนหน้าอาจถูกปรับออกไปเมื่อใดก็ตามที่การทำเช่นนั้นจะเทียบเท่ากับผลกระทบของพวกเขาถูกยกเลิก ; มิฉะนั้นจะไม่สามารถ ดูตัวอย่างด้านล่าง
* หมายเหตุ:นี่คือไม่สอดคล้องกับUB เกิดขึ้นที่รวบรวมเวลา หากคอมไพเลอร์สามารถพิสูจน์ได้ว่ารหัส UB จะถูกเรียกใช้สำหรับอินพุตทั้งหมดเสมอดังนั้น UB สามารถขยายเวลาคอมไพล์ได้ อย่างไรก็ตามสิ่งนี้ต้องการให้ทราบว่าโค้ดก่อนหน้าทั้งหมดจะส่งคืนในที่สุดซึ่งเป็นข้อกำหนดที่เข้มงวด อีกครั้งดูตัวอย่าง / คำอธิบายด้านล่าง
เพื่อให้เป็นรูปธรรมโปรดทราบว่ารหัสต่อไปนี้ต้องพิมพ์foo
และรอการป้อนข้อมูลของคุณโดยไม่คำนึงถึงพฤติกรรมที่ไม่ได้กำหนดใด ๆ ที่ตามมา:
printf("foo")
getchar()
*(char*)1 = 1
อย่างไรก็ตามโปรดทราบว่าไม่มีการรับประกันว่าfoo
จะยังคงอยู่บนหน้าจอหลังจาก UB เกิดขึ้นหรือตัวอักษรที่คุณพิมพ์จะไม่อยู่ในบัฟเฟอร์อินพุตอีกต่อไป การดำเนินการทั้งสองนี้สามารถ "เลิกทำได้" ซึ่งมีผลคล้ายกับ UB "การเดินทางข้ามเวลา"
หากไม่มีgetchar()
บรรทัดนั้นจะเป็นเรื่องถูกกฎหมายที่จะปรับให้เหมาะสมที่สุดก็ต่อเมื่อสิ่งนั้นจะแยกไม่ออกจากการแสดงผลfoo
แล้ว "ไม่ทำ"
หรือไม่ว่าทั้งสองจะแยกไม่ออกจะขึ้นอยู่ทั้งหมดในการดำเนินงาน (เช่นในคอมไพเลอร์และไลบรารีมาตรฐานของคุณ) ตัวอย่างเช่นคุณสามารถprintf
บล็อกเธรดของคุณที่นี่ในขณะที่รอให้โปรแกรมอื่นอ่านผลลัพธ์ได้หรือไม่ หรือจะกลับทันที?
หากสามารถบล็อกที่นี่ได้แสดงว่าโปรแกรมอื่นสามารถปฏิเสธที่จะอ่านผลลัพธ์ทั้งหมดและอาจไม่กลับมาอีกและด้วยเหตุนี้ UB อาจไม่เกิดขึ้นจริง
ถ้ามันสามารถกลับมาที่นี่ได้ทันทีเราก็รู้ว่ามันจะต้องกลับมาดังนั้นการปรับให้เหมาะสมที่สุดจึงแยกไม่ออกจากการเรียกใช้งานและยกเลิกการทำเอฟเฟกต์ของมัน
แน่นอนว่าเนื่องจากคอมไพลเลอร์รู้ว่าพฤติกรรมใดที่อนุญาตให้ใช้กับเวอร์ชันใดเวอร์ชันหนึ่งprintf
จึงสามารถปรับให้เหมาะสมตามนั้นและprintf
อาจได้รับการปรับให้เหมาะสมในบางกรณีไม่ใช่อย่างอื่น แต่อีกครั้งเหตุผลก็คือสิ่งนี้จะแยกไม่ออกจากการที่ UB ยกเลิกการดำเนินการก่อนหน้านี้ไม่ใช่ว่ารหัสก่อนหน้านี้ "วางยา" เนื่องจาก UB
a
ไม่ได้ใช้ (ยกเว้นสำหรับการคำนวณเอง) และเพียงลบa