เหตุใด Clang / LLVM จึงเตือนฉันเกี่ยวกับการใช้ค่าเริ่มต้นในคำสั่ง switch ที่ครอบคลุมทุกกรณีที่แจกแจง?


34

พิจารณาคำสั่ง enum และ switch ต่อไปนี้:

typedef enum {
    MaskValueUno,
    MaskValueDos
} testingMask;

void myFunction(testingMask theMask) {
    switch (theMask) {
        case MaskValueUno: {}// deal with it
        case MaskValueDos: {}// deal with it
        default: {} //deal with an unexpected or uninitialized value
    }
};

ฉันเป็นโปรแกรมเมอร์ Objective-C แต่ฉันเขียนสิ่งนี้ใน C บริสุทธิ์สำหรับผู้ชมที่กว้างขึ้น

Clang / LLVM 4.1 ด้วย - ทุกอย่างเตือนฉันที่บรรทัดเริ่มต้น:

ฉลากเริ่มต้นในสวิตช์ซึ่งครอบคลุมค่าการแจงนับทั้งหมด

ทีนี้ฉันสามารถดูว่าทำไมถึงมีอยู่: ในโลกที่สมบูรณ์แบบค่าเดียวที่เข้าสู่การโต้แย้งtheMaskจะอยู่ใน enum ดังนั้นจึงไม่จำเป็นต้องมีค่าเริ่มต้น แต่จะเกิดอะไรขึ้นถ้าแฮ็กบางตัวเข้ามาและส่ง int ที่ไม่ได้กำหนดค่าเริ่มต้นไปยังฟังก์ชันที่สวยงาม ฟังก์ชั่นของฉันจะได้รับการจัดวางไว้ในห้องสมุดและฉันไม่สามารถควบคุมสิ่งที่จะเข้าไปได้ การใช้defaultเป็นวิธีการจัดการที่เป็นระเบียบ

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


1
ฉันควรพูดว่าเหตุผลของฉัน - ทุกอย่างคือการทำให้ตัวเองเป็นโปรแกรมเมอร์ที่ดีขึ้น ในฐานะที่เป็น NSHipster กล่าวว่า"Pro tip: Try setting the -Weverything flag and checking the “Treat Warnings as Errors” box your build settings. This turns on Hard Mode in Xcode." :
Swizzlr

2
-Weverythingอาจมีประโยชน์ แต่ควรระวังเกี่ยวกับการกลายพันธุ์รหัสของคุณมากเกินไปที่จะจัดการกับมัน คำเตือนบางอย่างนั้นไม่เพียง แต่ไร้ค่าเท่านั้น (อันที่จริงมันเป็นกรณีการใช้งานสำหรับ-Weverything: เริ่มต้นด้วยและปิดสิ่งที่ไม่สมเหตุสมผล)
สตีเฟ่นฟิชเชอร์

คุณช่วยขยายข้อความเตือนสำหรับลูกหลานหน่อยได้ไหม? โดยปกติจะมีมากกว่านั้น
สตีเวนฟิชเชอร์

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

@StevenFisher นั่นคือคำเตือนทั้งหมด และดังที่ Killian ชี้ให้เห็นถ้าฉันแก้ไข enum ของฉันในภายหลังมันจะเปิดโอกาสให้ค่าที่ถูกต้องส่งผ่านไปยังการใช้งานเริ่มต้น ดูเหมือนว่าจะเป็นรูปแบบการออกแบบที่ดี (ถ้าเป็นเช่นนั้น)
Swizzlr

คำตอบ:


31

ต่อไปนี้เป็นเวอร์ชันที่ไม่ได้รับผลกระทบจากการรายงานปัญหาหรือเสียงที่คุณกำลังป้องกัน:

void myFunction(testingMask theMask) {
    assert(theMask == MaskValueUno || theMask == MaskValueDos);
    switch (theMask) {
        case MaskValueUno: {}// deal with it
        case MaskValueDos: {}// deal with it
    }
}

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

ตอนนี้คุณกังวลว่ามีใครบางคนสามารถเรียกฟังก์ชั่นของคุณด้วยค่าที่อยู่นอกเหนือการแจกแจง ฟังดูเหมือนล้มเหลวที่จะทำตามข้อกำหนดเบื้องต้นของฟังก์ชั่น: มีการบันทึกไว้เพื่อคาดหวังค่าจากการtestingMaskแจงนับ แต่โปรแกรมเมอร์ได้ผ่านสิ่งอื่นไปแล้ว เพื่อให้ว่าข้อผิดพลาดโปรแกรมเมอร์ใช้assert()(หรือNSCAssert()ตามที่คุณบอกว่าคุณกำลังใช้ Objective-C) ทำให้โปรแกรมของคุณทำงานผิดพลาดโดยมีข้อความอธิบายว่าโปรแกรมเมอร์กำลังทำผิดถ้าโปรแกรมเมอร์ทำผิด


6
+1 เป็นการปรับเปลี่ยนเล็กน้อยฉันต้องการให้แต่ละกรณีreturn;และเพิ่มassert(false);จุดสิ้นสุด (แทนที่จะทำซ้ำตัวเองด้วยการระบุรายชื่อ enums ทางกฎหมายในตอนเริ่มต้นassert()และในswitch)
Josh Kelley

1
จะเกิดอะไรขึ้นถ้า Enum ที่ไม่ถูกต้องไม่ได้ถูกส่งผ่านโดยโปรแกรมเมอร์ที่เป็นใบ้ แต่เกิดจากข้อผิดพลาดของหน่วยความจำเสียหาย? เมื่อคนขับกดตัวแบ่งของโตโยต้าและข้อผิดพลาดทำให้ enum เกิดความเสียหายโปรแกรมจัดการเบรคควรหยุดทำงานและเบิร์นและควรมีข้อความแสดงต่อผู้ขับขี่: "โปรแกรมเมอร์ทำผิดโปรแกรมเมอร์แย่! " ฉันไม่เห็นเลยว่าสิ่งนี้จะช่วยผู้ใช้อย่างไรก่อนที่พวกเขาจะขับผ่านขอบหน้าผา

2
@Lundin เป็นสิ่งที่ OP กำลังทำอยู่หรือว่าเป็นกรณีที่ไม่มีเหตุผลเชิงทฤษฎีที่คุณเพิ่งสร้างมา โดยไม่คำนึงถึง "ความผิดพลาดของหน่วยความจำเสียหาย" [i] เป็นข้อผิดพลาดของโปรแกรม [ii] ไม่ใช่สิ่งที่คุณสามารถดำเนินการต่อจากวิธีที่มีความหมาย (อย่างน้อยก็ไม่ใช่ข้อกำหนดที่ระบุไว้ในคำถาม)

1
@ GrahamLee ฉันแค่บอกว่า "วางและตาย" ไม่จำเป็นต้องเป็นตัวเลือกที่ดีที่สุดเมื่อคุณพบข้อผิดพลาดที่ไม่คาดคิด

1
มีปัญหาใหม่ที่คุณอาจปล่อยให้การยืนยันและกรณีที่เกิดขึ้นจากการซิงค์โดยไม่ตั้งใจ
253751

9

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

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


1
แต่ข้อกังวลของฉันคือตัวแปรที่สกปรกและป้องกันสิ่งนั้น (เช่นอย่างที่ฉันบอกว่า int ที่ไม่มีการกำหนดค่าเริ่มต้น) สำหรับฉันแล้วดูเหมือนว่ามันจะเป็นไปได้ที่คำสั่งสวิตช์จะไปถึงค่าเริ่มต้นในสถานการณ์เช่นนี้
Swizzlr

ฉันไม่ทราบคำจำกัดความของ Objective-C โดยใจ แต่ฉันคิดว่าคอมไพเลอร์ end จะเป็น end ในคำอื่น ๆ ที่เป็น "เตรียม" ค่าเท่านั้นที่สามารถเข้าสู่วิธีการที่ถ้าโปรแกรมของคุณแล้วแสดงพฤติกรรมที่ไม่ได้กำหนดและฉันพบว่ามันทั้งหมดที่เหมาะสมที่คอมไพเลอร์ไม่ได้ใช้เวลาที่เข้าบัญชี
Kilian Foth

3
@Kilian ไม่ว่าพวกเขาจะไม่ Objective-C enums คือ C enums ไม่ใช่ Java enums ค่าใด ๆ จากชนิดอินทิกรัลสำคัญสามารถแสดงในอาร์กิวเมนต์ของฟังก์ชันได้

2
นอกจากนี้ enums สามารถตั้งค่าในรันไทม์จากจำนวนเต็ม ดังนั้นพวกเขาสามารถมีค่าใด ๆ เท่าที่จะเป็นไปได้

OP ถูกต้อง testMask m; myFunction (m); น่าจะเป็นกรณีเริ่มต้น
Matthew James Briggs

4

เสียงดังกังวานสับสนโดยมีคำสั่งเริ่มต้นที่มีการฝึกฝนที่ดีอย่างสมบูรณ์มันเป็นที่รู้จักกันในนามการเขียนโปรแกรมเชิงป้องกันและถือว่าเป็นแนวปฏิบัติที่ดีในการเขียนโปรแกรม (1) มันถูกใช้อย่างมากมายในระบบที่มีความสำคัญต่อภารกิจแม้ว่าอาจจะไม่ใช่ในการเขียนโปรแกรมเดสก์ท็อปก็ตาม

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

สำหรับสิ่งที่เขียนไว้ในคำสั่งเริ่มต้น ... หากคุณสงสัยว่าโปรแกรมนั้นมีปัญหาเมื่อคุณลงเอยที่นั่นคุณต้องจัดการข้อผิดพลาดบางอย่าง ในหลายกรณีคุณอาจเพียงแค่เพิ่มคำสั่งที่ว่างเปล่าที่มีความคิดเห็น: "ไม่คาดคิด แต่ไม่สำคัญ" ฯลฯ เพื่อแสดงว่าคุณได้ให้ความคิดกับสถานการณ์ที่ไม่น่าเป็นไปได้


(1) MISRA-C: 2004 15.3


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

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

2
@JensAyton มันสับสน เครื่องมือวิเคราะห์แบบสแตติกระดับมืออาชีพทั้งหมดรวมถึงคอมไพเลอร์ที่รองรับ MISRA ทั้งหมดจะให้คำเตือนหากคำสั่งสวิตช์ไม่มีคำสั่งเริ่มต้น ลองด้วยตัวคุณเอง

4
การเข้ารหัสไปยัง MISRA-C ไม่ได้เป็นการใช้งานที่ถูกต้องสำหรับคอมไพเลอร์ C เท่านั้นและ-Weverythingจะเปิดใช้งานการเตือนทุกครั้งไม่ใช่การเลือกที่เหมาะสมกับกรณีการใช้งานเฉพาะ ไม่เหมาะกับรสนิยมของคุณไม่เหมือนกับความสับสน
Jens Ayton

2
@Lundin: ฉันค่อนข้างแน่ใจว่าการติด MISRA-C ไม่ได้ทำให้โปรแกรมปลอดภัยและปราศจากข้อผิดพลาดอย่างน่าอัศจรรย์ ... และฉันก็แน่ใจเหมือนกันว่ามีรหัส C ปลอดภัยมากมายปราศจากข้อบกพร่องจากผู้ที่ไม่เคยแม้แต่จะรู้ได้ยิน MISRA ในความเป็นจริงมันเป็นอะไรที่มากกว่าความเห็นของใครบางคน (เป็นที่นิยม แต่ไม่ได้โต้แย้ง) และมีคนที่พบกฎบางอย่างโดยพลการและบางครั้งก็เป็นอันตรายนอกบริบทที่พวกเขาได้รับการออกแบบ
cHao

4

ยังดีกว่า:

typedef enum {
    MaskValueUno,
    MaskValueDos,

    MaskValue_count
} testingMask;

void myFunction(testingMask theMask) {
    assert(theMask >= 0 && theMask<MaskValue_count);
    switch theMask {
        case MaskValueUno: {}// deal with it
        case MaskValueDos: {}// deal with it
    }
};

นี่เป็นข้อผิดพลาดน้อยเมื่อเพิ่มรายการใน enum คุณสามารถข้ามการทดสอบสำหรับ> = 0 หากคุณทำให้ค่า enum ของคุณไม่ได้ลงนาม วิธีนี้ใช้ได้เฉพาะเมื่อคุณไม่มีช่องว่างในค่า enum ของคุณ แต่มักจะเป็นกรณี


2
นี่เป็นการทำให้ประเภทที่มีมลภาวะเป็นค่าที่คุณไม่ต้องการให้มีอยู่ในประเภทนั้น มันมีความคล้ายคลึงกับ WTF เก่าที่ดีที่นี่: thedailywtf.com/articles/What_Is_Truth_0x3f_
Martin Sugioarto

4

แต่จะเกิดอะไรขึ้นถ้าแฮ็คบางตัวเข้ามาและใส่ int ที่ไม่มีการกำหนดค่าไว้ในฟังก์ชั่นที่สวยงามของฉัน

จากนั้นคุณจะได้พฤติกรรมที่ไม่ได้กำหนดและคุณdefaultจะไร้ความหมาย ไม่มีอะไรที่คุณสามารถทำได้เพื่อทำให้ดีขึ้น

ให้ฉันชัดเจนยิ่งขึ้น ทันทีที่มีคนส่งผ่านค่าเริ่มต้นintไปยังฟังก์ชันของคุณนั่นคือพฤติกรรมที่ไม่ได้กำหนด ฟังก์ชั่นของคุณสามารถแก้ปัญหาการหยุดชะงักและไม่เป็นไร มันคือ UB ไม่มีอะไรที่คุณสามารถทำได้เมื่อมีการเรียกใช้ UB


3
วิธีการเกี่ยวกับการบันทึกหรือโยนข้อยกเว้นแทนถ้าไม่สนใจมันเงียบ ๆ ?
jgauffin

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

1
ไม่มันจะไม่จัดการอะไร มันคือ UB โปรแกรมนี้มี UB เมื่อมีการป้อนฟังก์ชั่นและตัวฟังก์ชันไม่สามารถทำอะไรได้เลย
DeadMG

2
@DeadMG enum สามารถมีค่าใด ๆ ที่ชนิดจำนวนเต็มที่สอดคล้องกันในการใช้งานอาจมี ไม่มีอะไรเกี่ยวกับมัน การเข้าถึงเนื้อหาของตัวแปรอัตโนมัติที่ไม่ได้กำหนดค่าเริ่มต้นนั้นเป็น UB แต่ "แฮ็คที่ชั่วร้าย" (ซึ่งน่าจะเป็นข้อผิดพลาดบางอย่าง) อาจโยนค่าที่กำหนดไว้อย่างดีถึงแม้ว่ามันจะไม่ใช่หนึ่งในค่า ระบุไว้ในประกาศ enum

2

คำสั่งเริ่มต้นไม่จำเป็นต้องช่วย หากสวิตช์อยู่เหนือ enum ค่าใด ๆ ที่ไม่ได้กำหนดไว้ใน enum จะสิ้นสุดลงในการเรียกใช้งานพฤติกรรมที่ไม่ได้กำหนด

สำหรับทุกสิ่งที่คุณรู้คอมไพเลอร์สามารถรวบรวมสวิตช์นั้น (พร้อมค่าเริ่มต้น) เป็น:

if (theMask == MaskValueUno)
  // Execute something MaskValueUno code
else // theMask == MaskValueDos
  // Execute MaskValueDos code

เมื่อคุณทริกเกอร์พฤติกรรมที่ไม่ได้กำหนดจะไม่มีการย้อนกลับ


2
ประการแรกมันเป็นค่าที่ไม่ระบุไม่ใช่พฤติกรรมที่ไม่ได้กำหนด ซึ่งหมายความว่าคอมไพเลอร์อาจถือว่าค่าอื่น ๆ ที่สะดวกกว่า แต่มันอาจไม่เปลี่ยนดวงจันทร์ให้กลายเป็นชีสสีเขียวและอื่น ๆ ประการที่สองเท่าที่ฉันสามารถบอกได้ว่ามันใช้ได้กับ C ++ เท่านั้น ใน C ช่วงของค่าของenumประเภทจะเหมือนกับช่วงของค่าของประเภทจำนวนเต็มพื้นฐาน (ซึ่งเป็นการกำหนดการนำไปปฏิบัติดังนั้นจึงต้องสอดคล้องกันด้วยตนเอง)
Jens Ayton

1
อย่างไรก็ตามอินสแตนซ์ของตัวแปร enum และค่าคงที่การแจงนับไม่จำเป็นต้องมีความกว้างและการเซ็นเหมือนกันทั้งคู่นั้นเป็น impl.d นิยาม แต่ฉันค่อนข้างแน่ใจว่า enums ทั้งหมดใน C จะถูกประเมินเหมือนกับประเภทจำนวนเต็มของพวกเขาดังนั้นจึงไม่มีพฤติกรรมที่ไม่ได้กำหนดหรือแม้แต่ที่ไม่ได้ระบุไว้ที่นั่น

2

ฉันยังต้องการที่จะมีdefault:ในทุกกรณี ฉันไปงานเลี้ยงตามปกติ แต่ ... ความคิดอื่นที่ฉันไม่เห็นด้านบน:

  • คำเตือนเฉพาะ (หรือข้อผิดพลาดหากมีการขว้างปา-Werror) มาจาก-Wcovered-switch-default( -Weverythingแต่ไม่ใช่-Wall) หากความยืดหยุ่นทางศีลธรรมของคุณอนุญาตให้คุณปิดคำเตือนบางอย่าง (เช่นตัดบางสิ่งจาก-Wallหรือ-Weverything) พิจารณาการขว้างปา-Wno-covered-switch-default(หรือ-Wno-error=covered-switch-defaultเมื่อใช้-Werror) และโดยทั่วไป-Wno-...สำหรับคำเตือนอื่น ๆ ที่คุณเห็นว่าไม่เหมาะสม
  • สำหรับgcc(และพฤติกรรมทั่วไปมากขึ้นในclang) ปรึกษาgccmanpage สำหรับ-Wswitch, -Wswitch-enum, -Wswitch-defaultสำหรับ (แตกต่างกัน) พฤติกรรมในสถานการณ์ที่คล้ายกันของระบุชนิดในงบสวิทช์
  • ฉันไม่ชอบคำเตือนในแนวคิดนี้และฉันไม่ชอบถ้อยคำของมัน สำหรับฉันคำจากคำเตือน ("ป้ายกำกับเริ่มต้น ... ครอบคลุมค่าทั้งหมด ... ") แนะนำว่าdefault:กรณีจะต้องถูกดำเนินการเสมอเช่น

    switch (foo) {
      case 1:
        do_something(); 
        //note the lack of break (etc.) here!
      default:
        do_default();
    }

    การอ่านครั้งแรกนี้คือสิ่งที่ผมคิดว่าคุณกำลังวิ่งเข้า - ที่ของคุณdefault:กรณีที่จะได้รับการดำเนินการเพราะไม่มีbreak;หรือreturn;หรือคล้ายกัน แนวคิดนี้เป็นที่คล้ายกัน (กับหูของฉัน) เพื่อพี่เลี้ยงสไตล์อื่น ๆ (แม้จะมีประโยชน์ในบางครั้ง) clangความเห็นที่พ่นออกมาจาก หากfoo == 1ทั้งสองฟังก์ชั่นจะถูกดำเนินการ รหัสของคุณด้านบนมีพฤติกรรมนี้ นั่นคือล้มเหลวในการแยกออกเฉพาะในกรณีที่คุณต้องการที่จะทำให้รันโค้ดจากกรณีที่ตามมา! อย่างไรก็ตามสิ่งนี้ดูเหมือนจะไม่เป็นปัญหาของคุณ

เมื่อมีความเสี่ยงในการเป็นคนพูดพล่อยๆ

  • อย่างไรก็ตามฉันคิดว่าพฤติกรรมนี้สอดคล้องกับการตรวจสอบประเภทที่ก้าวร้าวในภาษาอื่นหรือคอมไพเลอร์ หากในขณะที่คุณตั้งสมมติฐานว่าการเยาะเย้ยบางอย่างจะพยายามส่งผ่านintหรือบางสิ่งบางอย่างไปยังฟังก์ชั่นนี้ซึ่งมีเจตนาชัดเจนว่าจะบริโภครูปแบบเฉพาะของคุณเองคอมไพเลอร์ของคุณควรปกป้องคุณอย่างเท่าเทียมกัน แต่มันไม่ได้! (นั่นคือมันดูเหมือนว่าอย่างน้อยgccและclangไม่ได้ทำenumประเภทการตรวจสอบ แต่ผมได้ยินว่าiccไม่ ) เนื่องจากคุณไม่ได้รับประเภทความปลอดภัยคุณสามารถรับค่าความปลอดภัยตามที่กล่าวไว้ข้างต้น มิฉะนั้นตามที่แนะนำใน TFA ให้พิจารณาstructหรือสิ่งที่สามารถให้ความปลอดภัยประเภท
  • วิธีแก้ปัญหาอื่นอาจจะสร้างใหม่ "คุ้มค่า" ในenumเช่นMaskValueIllegalและไม่สนับสนุนว่าในของคุณcase switchที่จะถูกกินโดยdefault:(นอกเหนือจากค่าแปลกประหลาดอื่น ๆ )

ป้องกันการถ่ายทอดสดนาน!


1

นี่คือข้อเสนอแนะทางเลือก:
OP พยายามป้องกันกรณีที่มีคนผ่านไปในintที่ที่คาดว่าจะเป็นenum หรือมีโอกาสมากขึ้นที่บางคนเชื่อมโยงไลบรารีเก่ากับโปรแกรมที่ใหม่กว่าโดยใช้ส่วนหัวที่ใหม่กว่าซึ่งมีหลายกรณี

ทำไมไม่เปลี่ยนสวิตช์เพื่อจัดการintเคส? การเพิ่มการร่ายหน้าค่าในสวิตช์ช่วยกำจัดคำเตือนและยังให้ระดับของคำใบ้เกี่ยวกับสาเหตุที่มีค่าเริ่มต้น

void myFunction(testingMask theMask) {
    int maskValue = int(theMask);
    switch(maskValue) {
        case MaskValueUno: {} // deal with it
        case MaskValueDos: {}// deal with it
        default: {} //deal with an unexpected or uninitialized value
    }
}

ฉันพบนี้มากน้อยรังเกียจกว่าassert()การทดสอบแต่ละค่าเป็นไปได้หรือแม้กระทั่งการทำสมมติฐานที่ว่าช่วงของenumค่าเป็นอย่างดีที่สั่งซื้อเพื่อให้ง่ายงานทดสอบ นี่เป็นเพียงวิธีที่น่าเกลียดในการทำสิ่งที่ค่าเริ่มต้นทำอย่างแม่นยำและสวยงาม


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