การกระโดดข้ามการกำหนดค่าเริ่มต้นของตัวแปรไม่ถูกต้องหรือทำให้เกิดพฤติกรรมที่ไม่ได้กำหนดหรือไม่?


17

พิจารณารหัสนี้:

void foo()
{
    goto bar;
    int x = 0;
    bar: ;
}

GCC และ Clang ปฏิเสธเนื่องจากการข้ามไปยังการbar:ข้ามการกำหนดค่าเริ่มต้นของตัวแปร MSVC ไม่บ่นเลย (ยกเว้นการใช้xหลังจากbar:ทำให้เกิดการเตือน)

เราสามารถทำสิ่งเดียวกันด้วยswitch:

void foo()
{
    switch (0)
    {
        int x = 0;
        case 0: ;
    }
}

ตอนนี้ทั้งสามคอมไพเลอร์ปล่อยข้อผิดพลาด

ตัวอย่างเหล่านั้นไม่ดีหรือไม่ หรือพวกเขาทำให้ UB?

ฉันเคยคิดว่าทั้งสองรูปแบบไม่ดี แต่ฉันไม่สามารถหาส่วนที่น่ารำคาญของมาตรฐาน [stmt.goto]ไม่ได้พูดอะไรเกี่ยวกับเรื่องนี้และไม่ไม่[stmt.select]


1
ปัญหาจะไม่สำคัญหากคุณใช้xหลังจากการกระโดด
Jarod42

1
ไม่ใช่มาตรฐาน แต่ที่นี่มีข้อมูลบางส่วนที่สามารถค้นหาได้: en.cppreference.com/w/cpp/language/goto โดยเฉพาะ: "ถ้าการถ่ายโอนการควบคุมเข้าสู่ขอบเขตของตัวแปรอัตโนมัติใด ๆ (เช่นโดยการกระโดดไปข้างหน้าเหนือการประกาศ คำสั่ง) โปรแกรมไม่ถูกต้อง (ไม่สามารถคอมไพล์ได้) ยกเว้น ... "
idclev 463035818

เพิ่มการ/permissive-ตั้งค่าสถานะเพื่อ MSVC และมันจะบ่นเช่นกัน ฉันไม่ทราบว่าพฤติกรรมของ MSVC ที่ไม่มีธงนั้นมีการกำหนดไว้อย่างดีหรือไม่ (ฉันจะถือว่าเป็นอย่างอื่น
วอลนัท

@ วอลนัต"มิฉะนั้นทำไมพวกเขาถึงยอมให้มันเป็นไปได้"สำหรับความเข้ากันได้แบบย้อนหลังหรือเพราะพวกเขาไม่สนใจมาตรฐานมากเกินไป คอมไพเลอร์หลักทั้งหมดไม่เป็นไปตามมาตรฐานภายใต้การตั้งค่าเริ่มต้น
HolyBlackCat

คำตอบ:


20

มันไม่ถูกต้องเมื่อการเตรียมใช้งานไม่ว่างเปล่า

[stmt.dcl]

3เป็นไปได้ที่จะถ่ายโอนไปยังบล็อก แต่ไม่ใช่ในลักษณะที่ข้ามการประกาศด้วยการเริ่มต้น (รวมถึงสิ่งที่อยู่ในเงื่อนไขและข้อความเริ่มต้น) โปรแกรมที่กระโดดจากจุดที่ตัวแปรที่มีระยะเวลาการจัดเก็บอัตโนมัติไม่อยู่ในขอบเขตไปยังจุดที่อยู่ในขอบเขตจะมีรูปแบบไม่ดีเว้นแต่ตัวแปรนั้นจะมีการเริ่มต้นที่ว่างเปล่า ([basic.life]) ในกรณีเช่นนี้ตัวแปรที่มีการกำหนดค่าเริ่มต้นว่างจะถูกสร้างขึ้นตามลำดับการประกาศ

initializer ทำให้การกำหนดค่าเริ่มต้นไม่ว่างเปล่า ในทางตรงกันข้ามนี่

void foo()
{
    goto bar;
    int x; // no initializer
    bar: ;
}

จะมีรูปแบบที่ดี แม้ว่าคำเตือนทั่วไปเกี่ยวกับการใช้xกับค่าไม่แน่นอนจะนำไปใช้


การประกาศตัวแปรไม่จำเป็นต้องเป็นสิ่งแรกในขอบเขตใช่ไหม
Cruncher

4
@Cruncher - C89 ต้องการมัน C ++ ไม่เคยทำและไม่ทันสมัย ​​C อีกต่อไป
StoryTeller - Unslander Monica

3

จากคำสั่ง goto :

หากการถ่ายโอนการควบคุมเข้าสู่ขอบเขตของตัวแปรอัตโนมัติใด ๆ (เช่นโดยการกระโดดไปข้างหน้าเหนือคำแถลงการณ์ประกาศ) โปรแกรมนั้นมีรูปแบบไม่ดี (ไม่สามารถรวบรวมได้) ยกเว้นตัวแปรทั้งหมดที่มีการป้อนขอบเขตไว้

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