สีที่ตั้งไว้เป็นไปตามมาตรฐานคืออะไร?
ตอบด้วยเครื่องหมายคำพูดจากมาตรฐาน C ++ 11 และ C ++ 14:
[expr.static.cast] / 10
ค่าของประเภทการรวมหรือการแจงนับสามารถแปลงเป็นประเภทการแจงนับได้อย่างชัดเจน ค่าไม่เปลี่ยนแปลงหากค่าดั้งเดิมอยู่ภายในช่วงของค่าการแจงนับ (7.2) มิฉะนั้นค่าผลลัพธ์จะไม่ได้รับการระบุ (และอาจไม่อยู่ในช่วงนั้น)
ลองค้นหาช่วงของค่าการแจกแจง : [dcl.enum] / 7
สำหรับการแจงนับซึ่งชนิดพื้นฐานถูกแก้ไขค่าของการแจงนับเป็นค่าของชนิดที่ขีดเส้นใต้
ก่อน CWG 1766 (C ++ 11, C ++ 14)
ดังนั้นสำหรับdata[0] == 100
ค่าส่งผลให้มีการระบุ (*) และไม่มีพฤติกรรมที่ไม่ได้กำหนด (UB)มีส่วนเกี่ยวข้อง โดยทั่วไปในขณะที่คุณโยนจากประเภทต้นแบบชนิดนับค่าในไม่data[0]
สามารถนำไปสู่ UB static_cast
สำหรับ
หลังจาก CWG 1766 (C ++ 17)
ดูCWG ข้อบกพร่อง 1766 ย่อหน้า [expr.static.cast] p10 มีความเข้มแข็งดังนั้นตอนนี้คุณสามารถเรียกใช้ UB ได้ถ้าคุณส่งค่าที่อยู่นอกช่วงที่สามารถแสดงค่าของ enum เป็นชนิด enum ได้ สิ่งนี้ยังใช้ไม่ได้กับสถานการณ์ในคำถามเนื่องจากdata[0]
เป็นประเภทของการแจงนับ (ดูด้านบน)
โปรดทราบว่า CWG 1766 ถือเป็นข้อบกพร่องในมาตรฐานดังนั้นจึงเป็นที่ยอมรับสำหรับผู้ใช้งานคอมไพเลอร์เพื่อใช้กับโหมดการรวบรวม C ++ 11 และ C ++ 14
(*) char
จะต้องมีอย่างน้อย 8 บิตกว้าง unsigned
แต่ไม่จำเป็นต้องเป็น ต้องมีค่าสูงสุดที่สามารถจัดเก็บได้อย่างน้อย127
ต่อ Annex E ของมาตรฐาน C99
เปรียบเทียบกับ [expr] / 4
หากในระหว่างการประเมินผลของนิพจน์ผลลัพธ์จะไม่ถูกกำหนดทางคณิตศาสตร์หรือไม่อยู่ในช่วงของค่าที่สามารถแทนได้สำหรับประเภทของพฤติกรรมนั้นจะไม่ได้กำหนด
ก่อน CWG 1766 การแปลงชนิดหนึ่ง -> ประเภทการแจงนับสามารถผลิตมูลค่าไม่ระบุรายละเอียด คำถามคือ: ค่าที่ไม่ระบุสามารถอยู่นอกค่าที่สามารถแทนได้สำหรับประเภทของมันหรือไม่? ฉันเชื่อว่าคำตอบคือไม่ - ถ้าคำตอบคือใช่จะไม่มีความแตกต่างในการรับประกันที่คุณได้รับสำหรับการดำเนินการกับประเภทที่เซ็นชื่อระหว่าง "การดำเนินการนี้สร้างมูลค่าที่ไม่ระบุ" และ "การดำเนินการนี้มีพฤติกรรมที่ไม่ได้กำหนด"
ดังนั้นก่อนที่จะ CWG 2309 แม้static_cast<Color>(10000)
จะไม่เรียก UB; แต่หลังจาก CWG 1766 มันจะเรียกใช้ UB
ตอนนี้switch
คำสั่ง:
[stmt.switch] / 2
เงื่อนไขจะต้องเป็นประเภทหนึ่งประเภทการแจงนับหรือประเภทชั้นเรียน [... ] การส่งเสริมการขายแบบรวมจะดำเนินการ
[conv.prom] / 4
prvalue ของชนิดการแจงนับที่ไม่ครอบคลุมซึ่งชนิดพื้นฐานถูกแก้ไข (7.2) สามารถถูกแปลงเป็น prvalue ของชนิดพื้นฐาน ยิ่งไปกว่านั้นหากการส่งเสริมการขายแบบรวมสามารถนำไปใช้กับประเภทพื้นฐานของมันได้ส่วน prvalue ของประเภทการแจงนับที่ไม่มีประเภทที่มีการแก้ไขพื้นฐานยังสามารถถูกแปลงเป็น prvalue ของประเภทพื้นฐานที่เลื่อนขั้น
หมายเหตุ: ประเภทพื้นฐานของ enum ขอบเขต w / o enum ฐานint
คือ สำหรับ enscoped enums ประเภทพื้นฐานคือการใช้งานที่กำหนด แต่จะต้องไม่ใหญ่กว่าint
ถ้าint
สามารถมีค่าของตัวแจงนับทั้งหมด
สำหรับการแจงนับที่ไม่มีขอบเขตนี่จะนำเราไปสู่ / 1
prvalue ของจำนวนเต็มชนิดอื่นที่ไม่ใช่bool
, char16_t
, char32_t
หรือwchar_t
มีจำนวนเต็มแปลงยศ (4.13) น้อยกว่ายศint
สามารถแปลงเป็น prvalue ของประเภทint
ถ้าint
สามารถเป็นตัวแทนของค่าทั้งหมดของประเภทแหล่งที่มา มิฉะนั้น prvalue แหล่งที่สามารถแปลงเป็น prvalue unsigned int
ของประเภท
ในกรณีของการแจงนับที่ไม่ครอบคลุมเราจะติดต่อกับint
ที่นี่ สำหรับการระบุขอบเขต ( enum class
และenum struct
) จะไม่มีการส่งเสริมการขายหนึ่งรายการ ในทางใดทางหนึ่งโปรโมชั่นไม่นำไปสู่ UB int
ทั้งเป็นค่าที่เก็บไว้อยู่ในช่วงของประเภทพื้นฐานและในช่วงของ
[stmt.switch] / 5
เมื่อswitch
คำสั่งถูกดำเนินการสภาพของมันจะถูกประเมินและเปรียบเทียบกับค่าคงที่ของแต่ละกรณี หากหนึ่งในค่าคงที่ของเคสเท่ากับค่าของเงื่อนไขการควบคุมจะถูกส่งผ่านไปยังคำสั่งหลังcase
เลเบลที่ตรงกัน หากไม่มีcase
ค่าคงที่ตรงกับเงื่อนไขและหากมีdefault
ป้ายกำกับการควบคุมจะส่งผ่านไปยังข้อความที่ระบุโดยdefault
ฉลาก
default
ฉลากควรจะตี
หมายเหตุ: อาจดูที่โอเปอเรเตอร์การเปรียบเทียบ แต่ไม่ได้ใช้อย่างชัดเจนใน "การเปรียบเทียบ" ที่อ้างถึง ในความเป็นจริงไม่มีคำใบ้ว่าจะแนะนำ UB สำหรับขอบเขตที่ไม่มีขอบเขต
เป็นมาตรฐานมาตรฐานทำรับประกันใด ๆ เกี่ยวกับเรื่องนี้ แต่มี enum ธรรมดาหรือไม่?
การenum
กำหนดขอบเขตไม่ได้สร้างความแตกต่างที่นี่หรือไม่ อย่างไรก็ตามมันจะสร้างความแตกต่างว่าประเภทพื้นฐานได้รับการแก้ไขหรือไม่ ความสมบูรณ์ [decl.enum] / 7 คือ:
สำหรับการแจงนับซึ่งชนิดพื้นฐานถูกแก้ไขค่าของการแจงนับเป็นค่าของชนิดที่ขีดเส้นใต้ มิฉะนั้นการแจงนับกรณีที่อีนาทีเป็นที่เล็กที่สุดแจงนับและอีแม็กซ์ที่ใหญ่ที่สุดคือค่านิยมของการแจกแจงที่มีค่าในช่วงขนาทีเพื่อb สูงสุดที่กำหนดไว้ดังต่อไปนี้: ให้K
เป็น1
ตัวแทนเติมเต็มสองและ0
สำหรับ ส่วนเสริมหรือการเป็นตัวแทนของขนาดสัญญาณ b maxคือค่าที่เล็กที่สุดที่มากกว่าหรือเท่ากับmax (| e min | - K
, | e max |)และเท่ากับ2M - 1โดยที่M
เป็นจำนวนเต็มไม่เป็นลบ b minเป็นศูนย์ถ้า e minไม่ใช่ค่าลบและ - (b max + K
) เป็นอย่างอื่น
ลองมาดูการแจงนับต่อไปนี้:
enum ColorUnfixed /* no fixed underlying type */
{
red = 0x1,
yellow = 0x2
}
โปรดทราบว่าเราไม่สามารถกำหนดสิ่งนี้ให้เป็น enum ที่กำหนดขอบเขตได้เนื่องจาก enums ที่กำหนดขอบเขตทั้งหมดมีประเภทของข้อมูลอ้างอิงที่คงที่
โชคดีColorUnfixed
ที่ตัวแจงนับที่เล็กที่สุดคือred = 0x1
ดังนั้นmax (| e min | - K
, | e max |)เท่ากับ| e max | ในกรณีใด ๆ yellow = 0x2
ซึ่งเป็น ค่าที่น้อยที่สุดซึ่งมากกว่าหรือเท่ากับ2
ซึ่งเท่ากับ2 M - 1สำหรับจำนวนเต็มบวกM
คือ3
( 2 2 - 1 ) (ผมคิดว่าเจตนาคือการช่วยให้ช่วงที่มีขอบเขตใน 1 บิตขั้นตอน.) มันตามที่ขสูงสุดเป็น3
และbmin0
คือ
ดังนั้น100
จะอยู่นอกช่วงColorUnfixed
และstatic_cast
จะสร้างค่าที่ไม่ระบุก่อน CWG 1766 และพฤติกรรมที่ไม่ได้กำหนดหลังจาก CWG 1766
char
ดังนั้น "ค่าจะไม่เปลี่ยนแปลงหากค่าเดิมอยู่ในช่วงของค่าการแจงนับ (7.2)" มีผลบังคับใช้