เพื่อเพิ่มคำตอบที่นี่ฉันคิดว่ามันมีมูลค่าการพิจารณาคำถามตรงข้ามร่วมกับนี้ ได้แก่ เหตุใด C อนุญาตให้ล้มลงตั้งแต่แรก
หลักสูตรการเขียนโปรแกรมภาษาใด ๆ ให้บริการสองเป้าหมาย:
- ให้คำแนะนำกับคอมพิวเตอร์
- ออกจากบันทึกของความตั้งใจของโปรแกรมเมอร์
การสร้างภาษาการเขียนโปรแกรมใด ๆ จึงเป็นความสมดุลระหว่างวิธีการให้บริการสองเป้าหมายที่ดีที่สุด ในอีกด้านหนึ่งก็ง่ายขึ้นที่จะเปลี่ยนเป็นคำสั่งคอมพิวเตอร์ (ไม่ว่าจะเป็นรหัสเครื่องรหัสไบต์เช่น IL หรือคำแนะนำในการดำเนินการ) แล้วยิ่งสามารถประมวลผลหรือตีความจะมีประสิทธิภาพเชื่อถือได้และ ขนาดกะทัดรัดในการส่งออก นำมาซึ่งความสุดยอดเป้าหมายนี้ส่งผลให้เกิดการเขียนในการประกอบ IL หรือแม้แต่รหัส op-raw เพราะการคอมไพล์ที่ง่ายที่สุดคือการที่ไม่มีการคอมไพล์เลย
ในทางกลับกันภาษาที่แสดงความตั้งใจของโปรแกรมเมอร์มากกว่าวิธีการที่นำไปสู่จุดสิ้นสุดนั้นยิ่งโปรแกรมสามารถเข้าใจได้มากขึ้นทั้งเมื่อเขียนและในระหว่างการบำรุงรักษา
ตอนนี้switch
สามารถคอมไพล์ได้เสมอโดยแปลงเป็นเชนเทียบเท่าif-else
บล็อกหรือคล้ายกัน แต่มันถูกออกแบบมาเพื่อให้คอมไพล์ในรูปแบบแอสเซมบลีทั่วไปโดยเฉพาะที่หนึ่งใช้ค่าคำนวณออฟเซ็ตจากมัน (ไม่ว่าจะมองตาราง จัดทำดัชนีโดยแฮชที่สมบูรณ์แบบของค่าหรือตามจำนวนจริงในค่า *) เป็นที่น่าสังเกตว่า ณ จุดนี้ในวันนี้การรวบรวม C # บางครั้งจะกลายswitch
เป็นสิ่งที่เทียบเท่าif-else
และบางครั้งใช้วิธีการกระโดดแบบแฮชอิง (และเช่นเดียวกันกับ C, C ++ และภาษาอื่นที่มีไวยากรณ์เปรียบเทียบ)
ในกรณีนี้มีสองเหตุผลที่ดีในการอนุญาตให้ล้มลง:
มันเกิดขึ้นเองตามธรรมชาติอยู่แล้ว: ถ้าคุณสร้างตารางการกระโดดเป็นชุดของคำสั่งและหนึ่งในชุดคำสั่งก่อนหน้านี้ไม่มีการกระโดดหรือกลับการเรียงลำดับบางอย่าง การอนุญาตให้ล้มลงคือสิ่งที่จะ "เพิ่งเกิดขึ้น" หากคุณเปลี่ยนswitch
-using C ให้เป็นตารางกระโดดโดยใช้รหัสเครื่อง
ผู้เขียนที่เขียนในแอสเซมบลีเคยชินกับการเทียบเท่า: เมื่อเขียนตารางการกระโดดด้วยมือในการชุมนุมพวกเขาจะต้องพิจารณาว่าบล็อกของรหัสที่กำหนดจะจบลงด้วยการกลับมากระโดดนอกตารางหรือเพียงแค่ดำเนินการต่อ ไปยังบล็อกถัดไป เช่นนี้การมี coder เพิ่มอย่างชัดเจนbreak
เมื่อจำเป็นคือ "ธรรมชาติ" สำหรับ coder ด้วย
ดังนั้นในเวลานั้นจึงเป็นความพยายามที่สมเหตุสมผลในการปรับสมดุลสองเป้าหมายของภาษาคอมพิวเตอร์เนื่องจากเกี่ยวข้องกับทั้งรหัสเครื่องที่ผลิตและการแสดงออกของซอร์สโค้ด
สี่ทศวรรษต่อมาแม้ว่าสิ่งต่าง ๆ จะไม่เหมือนกันด้วยเหตุผลบางประการ:
- โคเดกใน C วันนี้อาจมีประสบการณ์การประกอบน้อยหรือไม่มีเลย ผู้เขียนโค้ดในภาษา C-style อื่น ๆ มีแนวโน้มที่จะน้อยลง (โดยเฉพาะ Javascript!) แนวคิดของ "สิ่งที่ผู้คนคุ้นเคยจากการชุมนุม" ไม่เกี่ยวข้องอีกต่อไป
- การปรับปรุงในการปรับให้เหมาะสมหมายความว่าโอกาสที่
switch
จะกลายเป็นif-else
เพราะมันถือว่าเป็นแนวทางที่น่าจะมีประสิทธิภาพมากที่สุดหรืออื่น ๆ กลายเป็นตัวแปรที่เป็นความลับโดยเฉพาะอย่างยิ่งของวิธีการกระโดดตารางที่สูงขึ้น การทำแผนที่ระหว่างวิธีการระดับสูงและระดับล่างไม่แข็งแรงเท่าที่เคยเป็นมา
- ประสบการณ์แสดงให้เห็นว่าการตกผ่านมีแนวโน้มที่จะเป็นกรณีของชนกลุ่มน้อยมากกว่าปกติ (การศึกษาคอมไพเลอร์ของซันพบว่า 3% ของ
switch
บล็อกใช้การหล่นผ่านนอกเหนือจากฉลากหลาย ๆ ตัวในบล็อกเดียวกันและคิดว่าการใช้งาน - กรณีที่นี่หมายความว่า 3% นี้เป็นจริงสูงกว่าปกติ) ดังนั้นภาษาที่ศึกษาทำให้ผิดปกติได้ง่ายกว่ามาก
- ประสบการณ์ได้แสดงให้เห็นว่าการล้มผ่านมีแนวโน้มที่จะเป็นแหล่งที่มาของปัญหาทั้งในกรณีที่มีการทำโดยไม่ตั้งใจและในกรณีที่มีคนพลาดการแก้ไขรหัสผ่านที่ถูกต้อง สิ่งหลังนี้เป็นส่วนเพิ่มเติมที่ละเอียดอ่อนของข้อบกพร่องที่เกี่ยวข้องกับการร่วงผ่านเนื่องจากถึงแม้ว่ารหัสของคุณจะไม่มีข้อบกพร่องอย่างสมบูรณ์แบบการตกผ่านของคุณยังสามารถทำให้เกิดปัญหาได้
เกี่ยวข้องกับจุดสองจุดสุดท้ายเหล่านั้นให้พิจารณาข้อความต่อไปนี้จาก K&R ฉบับปัจจุบัน:
การล้มจากกรณีหนึ่งไปยังอีกกรณีหนึ่งนั้นไม่น่าเชื่อถือเนื่องจากมีแนวโน้มที่จะแตกตัวเมื่อโปรแกรมถูกปรับเปลี่ยน ด้วยข้อยกเว้นของป้ายกำกับหลายป้ายสำหรับการคำนวณเดียวควรใช้การร่วงหล่นอย่าง จำกัด และแสดงความคิดเห็น
เป็นเรื่องของรูปแบบที่ดีให้หยุดพักหลังจากกรณีสุดท้าย (ค่าเริ่มต้นที่นี่) แม้ว่าจะไม่จำเป็นต้องมีเหตุผล บางวันเมื่อมีกรณีอื่นเข้ามาในตอนท้ายการเขียนโปรแกรมป้องกันแบบนี้จะช่วยคุณได้
ดังนั้นจากปากม้าการร่วงหล่นใน C จึงเป็นปัญหา ถือว่าเป็นแนวปฏิบัติที่ดีที่จะบันทึกการตกอยู่ในความคิดเห็นซึ่งเป็นแอปพลิเคชันของหลักการทั่วไปที่ควรจัดทำเอกสารในที่ที่ทำสิ่งผิดปกติเพราะนั่นคือสิ่งที่จะเดินทางไปตรวจสอบรหัสในภายหลังและ / หรือทำให้โค้ดของคุณดูเหมือน มีบั๊กของสามเณรอยู่ในนั้นเมื่อมันถูกต้องจริง
และเมื่อคุณคิดถึงมันรหัสเช่นนี้:
switch(x)
{
case 1:
foo();
/* FALLTHRU */
case 2:
bar();
break;
}
กำลังเพิ่มบางสิ่งเพื่อทำให้การล่มสลายชัดเจนในโค้ดไม่ใช่สิ่งที่สามารถตรวจพบได้ (โดยที่คอมไพเลอร์ตรวจพบ
ดังนั้นความจริงที่ว่าจะต้องมีความชัดเจนในการล้มใน C # ไม่ได้เพิ่มโทษให้กับคนที่เขียนได้ดีในภาษา C สไตล์อื่น ๆ ต่อไปเนื่องจากพวกเขาจะมีความชัดเจนใน fall-throughs ของพวกเขาแล้ว†
ในที่สุดการใช้goto
ที่นี่เป็นบรรทัดฐานจาก C และภาษาอื่น ๆ :
switch(x)
{
case 0:
case 1:
case 2:
foo();
goto below_six;
case 3:
bar();
goto below_six;
case 4:
baz();
/* FALLTHRU */
case 5:
below_six:
qux();
break;
default:
quux();
}
ในกรณีเช่นนี้ที่เราต้องการให้บล็อกรวมอยู่ในโค้ดที่ดำเนินการสำหรับค่าอื่นนอกเหนือจากที่นำมาหนึ่งบล็อกก่อนหน้านี้แล้วเราต้องใช้goto
แล้ว (แน่นอนว่ามีวิธีการและวิธีการหลีกเลี่ยงปัญหานี้ด้วยเงื่อนไขที่แตกต่างกัน แต่นั่นเป็นเรื่องจริงสำหรับทุกสิ่งที่เกี่ยวข้องกับคำถามนี้) เช่น C # ที่สร้างขึ้นด้วยวิธีปกติแล้วจัดการกับสถานการณ์หนึ่งที่เราต้องการกดรหัสมากกว่าหนึ่งบล็อกใน a switch
และเพียงแค่วางให้ครอบคลุมถึง fall-through เช่นกัน นอกจากนี้ยังทำให้ทั้งสองกรณีสะดวกและจัดทำเอกสารด้วยตนเองเนื่องจากเราต้องเพิ่มป้ายกำกับใหม่ใน C แต่สามารถใช้case
เป็นป้ายกำกับใน C # ได้ ใน C # เราสามารถกำจัดbelow_six
ฉลากและใช้goto case 5
ที่ชัดเจนว่าเรากำลังทำอะไร (เราต้องเพิ่มด้วยbreak
สำหรับdefault
, ซึ่งฉันทิ้งไว้เพียงเพื่อให้รหัส C ด้านบนไม่ชัดเจนรหัส C #)
โดยสรุปแล้ว:
- C # ไม่เกี่ยวข้องกับเอาท์พุทคอมไพเลอร์ที่ไม่ได้เพิ่มประสิทธิภาพเนื่องจากรหัส C ทำเมื่อ 40 ปีที่แล้ว (หรือ C วันนี้) ซึ่งทำให้แรงบันดาลใจของการตกที่ไม่เกี่ยวข้อง
- C # ยังคงเข้ากันได้กับ C ไม่ใช่แค่มีนัย
break
เพื่อการเรียนรู้ภาษาที่ง่ายขึ้นโดยผู้ที่คุ้นเคยกับภาษาที่คล้ายกันและการย้ายพอร์ตที่ง่ายขึ้น
- C # ลบแหล่งที่เป็นไปได้ของข้อบกพร่องหรือรหัสที่เข้าใจผิดที่ได้รับการบันทึกไว้อย่างดีว่าเป็นสาเหตุของปัญหาในช่วงสี่ทศวรรษที่ผ่านมา
- C # ทำให้แนวปฏิบัติที่ดีที่สุดที่มีอยู่กับ C (การตกลงผ่านเอกสาร) บังคับใช้โดยคอมไพเลอร์
- C # ทำให้กรณีที่ผิดปกติเป็นกรณีที่มีรหัสชัดเจนมากขึ้นและเป็นกรณีปกติที่มีรหัสหนึ่งเขียนโดยอัตโนมัติ
- C # ใช้วิธีการพื้นฐานเดียวกัน
goto
สำหรับการกดปุ่มบล็อกเดียวกันจากcase
ฉลากที่แตกต่างกันตามที่ใช้ใน C. มันแค่วางมันลงในกรณีอื่น ๆ
- C # ทำให้
goto
แนวทางที่ใช้สะดวกและชัดเจนกว่าใน C โดยอนุญาตให้case
ข้อความทำหน้าที่เป็นป้ายกำกับ
สรุปการออกแบบที่สมเหตุสมผล
* บางรูปแบบของ BASIC จะยอมให้ใครทำสิ่งที่ชอบGOTO (x AND 7) * 50 + 240
ในขณะที่เปราะและด้วยเหตุนี้จึงเป็นกรณีที่โน้มน้าวใจเป็นพิเศษสำหรับการห้ามgoto
ใช้เพื่อแสดงภาษาที่สูงกว่าเทียบเท่ากับวิธีที่รหัสระดับล่างสามารถกระโดดได้ เลขคณิตตามค่าซึ่งมีความเหมาะสมมากกว่าเมื่อผลลัพธ์ของการรวบรวมมากกว่าสิ่งที่ต้องได้รับการปรับปรุงด้วยตนเอง การใช้งานอุปกรณ์ของ Duff โดยเฉพาะอย่างยิ่งให้ยืมตัวเองดีกับรหัสเครื่องที่เทียบเท่าหรือ IL เพราะแต่ละบล็อกของคำแนะนำมักจะมีความยาวเท่ากันโดยไม่จำเป็นต้องเพิ่มnop
ตัวเติม
Device อุปกรณ์ของ Duff เกิดขึ้นที่นี่อีกครั้งเป็นข้อยกเว้นตามสมควร ความจริงที่ว่าด้วยรูปแบบดังกล่าวและที่คล้ายกันมีการทำซ้ำของการดำเนินการเพื่อให้การใช้งานของการล่มสลายค่อนข้างชัดเจนแม้จะไม่มีความเห็นอย่างชัดเจนถึงผลกระทบนั้น