เหตุใดการไหลออกจากจุดสิ้นสุดของฟังก์ชันที่ไม่ใช่โมฆะโดยไม่ส่งคืนค่าไม่ทำให้เกิดข้อผิดพลาดของคอมไพเลอร์


158

นับตั้งแต่ฉันรู้มาหลายปีแล้วว่าสิ่งนี้ไม่ได้สร้างข้อผิดพลาดตามค่าเริ่มต้น (อย่างน้อยใน GCC) ฉันสงสัยอยู่เสมอว่าเพราะอะไร

ฉันเข้าใจว่าคุณสามารถออกธงคอมไพเลอร์เพื่อสร้างคำเตือน แต่มันควรจะเป็นข้อผิดพลาดหรือไม่? ทำไมมันจึงสมเหตุสมผลสำหรับฟังก์ชั่นที่ไม่ใช่โมฆะไม่คืนค่าที่ถูกต้อง?

ตัวอย่างตามที่ร้องขอในความคิดเห็น:

#include <stdio.h>
int stringSize()
{
}

int main()
{
    char cstring[5];
    printf( "the last char is: %c\n", cstring[stringSize()-1] ); 
    return 0;
}

... คอมไพล์


9
อีกวิธีหนึ่งคือฉันจัดการกับคำเตือนทั้งหมด แต่มีข้อผิดพลาดเล็กน้อยและฉันเปิดใช้งานคำเตือนทั้งหมดที่ฉันสามารถทำได้ (ด้วยการปิดการใช้งานในท้องถิ่นหากจำเป็น ... แต่แล้วมันชัดเจนในรหัสว่าทำไม)
Matthieu M.

8
-Werror=return-typeจะถือว่าคำเตือนนั้นเป็นข้อผิดพลาด ฉันไม่สนใจคำเตือนและสองสามนาทีของความหงุดหงิดในการติดตามthisตัวชี้ที่ไม่ถูกต้องนำฉันมาที่นี่และข้อสรุปนี้
jozxyqk

นี่คือการทำให้แย่ลงโดยความจริงที่ว่าการไหลออกจากจุดสิ้นสุดของstd::optionalฟังก์ชั่นโดยไม่ต้องกลับมาส่งกลับตัวเลือก "ของจริง"
Rufus

@ รูฟัสมันไม่จำเป็นต้อง นั่นเป็นเพียงสิ่งที่เกิดขึ้นกับเครื่องของคุณ / คอมไพเลอร์ / OS / ดวงจันทร์ โค้ดอะไรก็ตามที่คอมไพเลอร์สร้างขึ้นเพราะพฤติกรรมที่ไม่ได้กำหนดเกิดขึ้นกับรูปลักษณ์ที่เป็นตัวเลือก 'ของจริง' ไม่ว่าจะเป็นอะไรก็ตาม
underscore_d

คำตอบ:


146

มาตรฐาน C99 และ C ++ ไม่ต้องการฟังก์ชันเพื่อคืนค่า คำสั่ง return ที่หายไปในฟังก์ชั่นคืนค่าจะถูกกำหนด (เพื่อส่งคืน0) เฉพาะในmainฟังก์ชั่น

เหตุผลรวมถึงการตรวจสอบว่าทุกเส้นทางรหัสคืนค่าค่อนข้างยากและค่าตอบแทนสามารถตั้งค่าด้วยแอสเซมบลีที่ฝังตัวหรือวิธีการที่ยุ่งยากอื่น ๆ

จากC ++ 11ฉบับร่าง:

§ 6.6.3 / 2

การไหลออกจากจุดสิ้นสุดของฟังก์ชั่น [... ] ส่งผลให้เกิดพฤติกรรมที่ไม่ได้กำหนดในฟังก์ชั่นการคืนค่า

§ 3.6.1 / 5

หากการควบคุมมาถึงจุดสิ้นสุดmainโดยไม่ต้องเผชิญกับreturn คำสั่งผลกระทบก็คือการดำเนินการ

return 0;

โปรดทราบว่าพฤติกรรมที่อธิบายใน C ++ 6.6.3 / 2 ไม่เหมือนกันใน C


gcc จะให้คำเตือนถ้าคุณเรียกมันด้วยตัวเลือก -Wreturn-type

- ประเภทเตือนกลับเมื่อใดก็ตามที่ฟังก์ชั่นที่ถูกกำหนดด้วยผลตอบแทนประเภทที่เริ่มต้นที่ int เตือนเกี่ยวกับคำสั่ง return ใด ๆ ที่ไม่มี return-value ในฟังก์ชั่นที่ return-type นั้นไม่ถือเป็นโมฆะ (การตกลงไปที่ท้ายฟังก์ชั่น body นั้นถือว่าคืนค่าโดยไม่มีค่า) และเกี่ยวกับ statement return ที่มี expression ในฟังก์ชัน return-type เป็นโมฆะ

คำเตือนนี้เปิดใช้งานโดย-Wall


เช่นเดียวกับความอยากรู้ให้ดูว่ารหัสนี้ทำอะไร:

#include <iostream>

int foo() {
   int a = 5;
   int b = a + 1;
}

int main() { std::cout << foo() << std::endl; } // may print 6

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


13
ฉันจะระแวดระวังในการเรียกพฤติกรรมที่ไม่ได้กำหนด "อนุญาต" แม้ว่าเป็นที่ยอมรับฉันก็ผิดที่จะเรียกมันว่า "ต้องห้าม" การไม่เป็นข้อผิดพลาดและไม่ต้องการการวินิจฉัยไม่เหมือนกับ "อนุญาต" อย่างน้อยที่สุดคำตอบของคุณจะอ่านเหมือนว่าคุณกำลังบอกว่าตกลงที่จะทำซึ่งส่วนใหญ่ไม่ใช่
การแข่งขัน Lightness ใน Orbit

4
@Catskul ทำไมคุณถึงซื้ออาร์กิวเมนต์นั้น มันจะเป็นไปได้หรือไม่ถ้าไม่ใช่เรื่องง่ายที่จะระบุจุดออกของฟังก์ชั่นและตรวจสอบให้แน่ใจว่าพวกเขาทั้งหมดคืนค่า (และค่าของชนิดส่งคืนที่ประกาศ)
BlueBomber

3
@Catskul ใช่และไม่ใช่ ภาษาที่พิมพ์แบบคงที่และ / หรือภาษาที่คอมไพล์ทำสิ่งต่าง ๆ มากมายที่คุณอาจพิจารณาว่า "ราคาแพงอย่างห้ามปราม" แต่เนื่องจากพวกเขาทำเพียงครั้งเดียวในเวลารวบรวมพวกเขามีค่าใช้จ่ายเล็กน้อย แม้จะกล่าวว่าฉันไม่เห็นว่าทำไมการระบุจุดออกของฟังก์ชั่นจะต้องเป็นแบบเชิงเส้น: คุณเพียงแค่สำรวจ AST ของฟังก์ชั่นแล้วมองหาการโทรกลับหรือออกจากการโทร นั่นคือเวลาเชิงเส้นซึ่งมีประสิทธิภาพอย่างแน่นอน
BlueBomber

3
@LightnessRacesinOrbit: หากฟังก์ชั่นที่มีค่าส่งคืนส่งคืนทันทีด้วยค่าและบางครั้งเรียกใช้ฟังก์ชันอื่นซึ่งมักจะออกจากผ่านthrowหรือlongjmpควรคอมไพเลอร์ต้องเข้าไม่ถึงreturnหลังจากการเรียกไปยังฟังก์ชันที่ไม่ส่งคืนหรือไม่? กรณีที่ไม่จำเป็นไม่ได้เป็นเรื่องธรรมดามากและข้อกำหนดในการรวมไว้แม้ในกรณีดังกล่าวอาจจะไม่เป็นภาระ แต่การตัดสินใจที่จะไม่ใช้มันก็สมเหตุสมผล
supercat

1
@supercat: คอมไพเลอร์อัจฉริยะที่ยอดเยี่ยมจะไม่เตือนหรือเกิดข้อผิดพลาดในกรณีดังกล่าว แต่ - อีกครั้ง - นี่เป็นสิ่งที่ไม่แน่นอนสำหรับกรณีทั่วไปดังนั้นคุณติดอยู่กับกฎทั่วไปของหัวแม่มือ ถ้าคุณรู้ว่าจุดสิ้นสุดของฟังก์ชั่นของคุณจะไม่สามารถเข้าถึงได้คุณก็ยังห่างไกลจากความหมายของการจัดการฟังก์ชั่นดั้งเดิมที่ใช่คุณสามารถไปข้างหน้าและทำสิ่งนี้และรู้ว่ามันปลอดภัย ตรงไปตรงมาคุณเป็นเลเยอร์ที่ต่ำกว่า C ++ ณ จุดนั้นและเช่นนั้นการรับประกันทั้งหมดของมันก็จะเป็นสิ่งที่สงสัยอยู่ดี
Lightness Races ที่ Orbit

42

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

Color getColor(Suit suit) {
    switch (suit) {
        case HEARTS: case DIAMONDS: return RED;
        case SPADES: case CLUBS:    return BLACK;
    }

    // Error, no return?
}

คุณโปรแกรมเมอร์รู้ดีว่าถ้าไม่นับบั๊กวิธีนี้จะส่งคืนสีเสมอ gcc วางใจว่าคุณรู้ว่าคุณกำลังทำอะไรอยู่มันไม่ได้บังคับให้คุณใส่ผลตอบแทนที่ด้านล่างของฟังก์ชั่น

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

char getChoice() {
    int ch = read();

    if (ch == -1 || ch == 'q') {
        System.exit(0);
    }
    else {
        return (char) ch;
    }

    // Cannot reach here, but still an error.
}

มันเป็นความแตกต่างทางปรัชญา C และ C ++ เป็นภาษาที่อนุญาตและเชื่อถือได้มากกว่า Java หรือ C # ดังนั้นข้อผิดพลาดบางอย่างในภาษาที่ใหม่กว่าคือคำเตือนใน C / C ++ และคำเตือนบางอย่างจะถูกละเว้นหรือปิดโดยปริยาย


2
หาก javac ตรวจสอบเส้นทางของรหัสแล้วจะไม่เห็นว่าคุณไม่สามารถไปถึงจุดนั้นได้หรือไม่
Chris Lutz

3
ในกรณีแรกมันไม่ได้ให้เครดิตคุณในการครอบคลุมเคส enum ทั้งหมด (คุณต้องใช้เคสเริ่มต้นหรือส่งคืนหลังจากเปลี่ยน) และในกรณีที่สองก็ไม่รู้ว่าSystem.exit()จะไม่กลับมา
John Kugelman

2
ดูเหมือนตรงไปตรงมาสำหรับ javac (คอมไพเลอร์ที่ทรงพลังอย่างอื่น) ที่จะรู้ว่าSystem.exit()ไม่มีวันกลับมา ฉันค้นหามัน ( java.sun.com/j2se/1.4.2/docs/api/java/lang/… ) และเอกสารก็บอกว่า "ไม่กลับมาปกติ" ฉันสงสัยว่าสิ่งที่หมายถึง ...
พอลบิ๊กการ์

@ พอล: มันหมายความว่าพวกเขาไม่ได้เป็นคนดี ภาษาอื่น ๆ ทั้งหมดพูดว่า "ไม่กลับมาปกติ" - กล่าวคือ "ไม่กลับมาใช้กลไกการส่งคืนปกติ"
Max Lybbert

1
ฉันต้องการคอมไพเลอร์ที่อย่างน้อยเตือนถ้าพบตัวอย่างแรกเพราะความถูกต้องของตรรกะจะแตกถ้าใครเพิ่มมูลค่าใหม่ให้ enum ฉันต้องการกรณีเริ่มต้นที่บ่นเสียงดังและ / หรือล้มเหลว (อาจใช้การยืนยัน)
Injektilo

14

คุณหมายถึงเหตุใดการไหลออกจากจุดสิ้นสุดของฟังก์ชันการส่งคืนค่า (เช่นการออกโดยไม่มีชัดแจ้งreturn) ไม่ใช่ข้อผิดพลาด

ประการแรกใน C ว่าฟังก์ชั่นส่งคืนสิ่งที่มีความหมายหรือไม่เป็นสิ่งสำคัญเฉพาะเมื่อรันโค้ดใช้ค่าที่ส่งคืนจริง ๆ บางทีภาษาอาจไม่ต้องการบังคับให้คุณส่งคืนสิ่งใดเมื่อคุณรู้ว่าคุณไม่ได้ใช้มันเป็นส่วนใหญ่

ประการที่สองเห็นได้ชัดว่าข้อกำหนดทางภาษาไม่ต้องการบังคับให้ผู้เขียนคอมไพเลอร์ตรวจสอบและตรวจสอบเส้นทางการควบคุมที่เป็นไปได้ทั้งหมดสำหรับการมีอยู่ของความชัดเจนreturn(แม้ว่าในหลายกรณีการทำเช่นนี้ไม่ยาก นอกจากนี้บางเส้นทางการควบคุมอาจนำไปสู่ฟังก์ชั่นที่ไม่ส่งคืนซึ่งเป็นลักษณะที่โดยทั่วไปจะไม่รู้จักคอมไพเลอร์ เส้นทางดังกล่าวอาจกลายเป็นแหล่งของผลบวกปลอมที่น่ารำคาญ

โปรดทราบว่า C และ C ++ แตกต่างกันในคำจำกัดความของพฤติกรรมในกรณีนี้ ใน C ++ เพียงไหลออกจากจุดสิ้นสุดของฟังก์ชั่นการส่งกลับค่าเป็นพฤติกรรมที่ไม่ได้กำหนดเสมอ ใน C ทำให้เกิดพฤติกรรมที่ไม่ได้กำหนดเฉพาะในกรณีที่รหัสโทรพยายามใช้ค่าที่ส่งคืน


+1 แต่ C ++ ไม่สามารถตัดreturnงบจากจุดสิ้นสุดได้main()หรือไม่
Chris Lutz

3
@ Chris Lutz: ใช่mainเป็นพิเศษในเรื่องนั้น
AnT

5

มันถูกกฎหมายภายใต้ C / C ++ ที่จะไม่ส่งคืนจากฟังก์ชันที่อ้างว่าส่งคืนบางสิ่ง มีหลายกรณีการใช้งานเช่นการโทรexit(-1)หรือฟังก์ชั่นที่เรียกมันหรือส่งข้อยกเว้น

คอมไพเลอร์จะไม่ปฏิเสธกฎหมาย C ++ แม้ว่าจะนำไปสู่ ​​UB หากคุณไม่ขอ โดยเฉพาะอย่างยิ่งคุณกำลังขอไม่มีคำเตือนการสร้าง(Gcc ยังคงเปิดบางอย่างโดยค่าเริ่มต้น แต่เมื่อเพิ่มเหล่านั้นดูเหมือนจะสอดคล้องกับคุณสมบัติใหม่ไม่ใช่คำเตือนใหม่สำหรับคุณสมบัติเก่า)

การเปลี่ยน no-arg gcc เริ่มต้นเพื่อส่งคำเตือนบางอย่างอาจเป็นการเปลี่ยนแปลงที่ไม่สมบูรณ์สำหรับสคริปต์ที่มีอยู่หรือสร้างระบบ คนที่ออกแบบมาอย่างดีทั้ง-Wallดีและจัดการกับคำเตือนหรือสลับคำเตือนของแต่ละบุคคล

การเรียนรู้ที่จะใช้โซ่เครื่องมือ C ++ เป็นอุปสรรคต่อการเรียนรู้ที่จะเป็นโปรแกรมเมอร์ C ++ แต่โซ่เครื่องมือ C ++ นั้นมักจะถูกเขียนโดยและสำหรับผู้เชี่ยวชาญ


ใช่Makefileฉันใช้-Wall -Wpedantic -Werrorแล้ว แต่นี่เป็นสคริปต์ทดสอบแบบครั้งเดียวที่ฉันลืมที่จะให้ข้อโต้แย้ง
คดีฟ้องร้องกองทุนโมนิก้า

2
เป็นตัวอย่างการทำ-Wduplicated-condส่วนหนึ่งของ-Wallbootstrap GCC ที่เสียหาย คำเตือนบางอย่างที่ดูเหมือนเหมาะสมในรหัสส่วนใหญ่ไม่เหมาะสมในรหัสทั้งหมด นั่นเป็นเหตุผลที่พวกเขาไม่ได้เปิดใช้งานโดยค่าเริ่มต้น
มีใครบางคนต้องการหุ่นกระบอก

ประโยคแรกของคุณดูเหมือนจะขัดแย้งกับคำพูดในคำตอบที่ยอมรับ "การไหลออก .... พฤติกรรมที่ไม่ได้กำหนด ... " หรือ ub ถูกพิจารณาว่าเป็น "ถูกกฎหมาย" หรือไม่? หรือคุณหมายถึงว่ามันไม่ใช่ UB เว้นแต่ว่าจะใช้ค่าที่ส่งคืน (ไม่ใช่) จริงหรือไม่? ฉันกังวลเกี่ยวกับกรณี C ++ btw
idclev 463035818

@ tobi303 int foo() { exit(-1); }ไม่ส่งคืนintจากฟังก์ชันที่ "อ้างว่าคืนค่า int" สิ่งนี้ถูกกฎหมายใน C ++ ตอนนี้ก็ไม่ได้กลับอะไร ; จุดสิ้นสุดของฟังก์ชันนั้นจะไม่ถึง การถึงจุดสิ้นสุดจริง ๆ แล้วfooจะเป็นพฤติกรรมที่ไม่ได้กำหนด ละเว้นกรณีสิ้นสุดกระบวนการint foo() { throw 3.14; }เรียกร้องให้ส่งคืนintแต่ไม่ทำเช่นนั้น
Yakk - Adam Nevraumont

1
ดังนั้นฉันเดาว่าvoid* foo(void* arg) { pthread_exit(NULL); }ใช้ได้ด้วยเหตุผลเดียวกัน (เมื่อมีการใช้งานผ่านเท่านั้นpthread_create(...,...,foo,...);)
idclev 463035818

1

ฉันเชื่อว่านี่เป็นเพราะรหัสดั้งเดิม (C ไม่จำเป็นต้องมีคำสั่ง return เช่น C ++) อาจมีรหัสฐานขนาดใหญ่ที่ต้องอาศัย "ฟีเจอร์" นั้น แต่อย่างน้อยก็มี-Werror=return-type แฟล็กสำหรับคอมไพเลอร์หลายตัว (รวมถึง gcc และ clang)


1

ในบางกรณีที่ จำกัด และเกิดขึ้นไม่บ่อยการไหลออกจากจุดสิ้นสุดของฟังก์ชั่นที่ไม่เป็นโมฆะโดยไม่ส่งคืนค่าอาจมีประโยชน์ ชอบรหัสเฉพาะ MSVC ต่อไปนี้:

double pi()
{
    __asm fldpi
}

ฟังก์ชันนี้คืนค่า pi โดยใช้ชุดประกอบ x86 ต่างจากแอสเซมบลีใน GCC ฉันรู้ว่าไม่มีวิธีใช้returnในการทำสิ่งนี้โดยไม่เกี่ยวข้องกับค่าใช้จ่ายในผลลัพธ์

เท่าที่ฉันรู้คอมไพเลอร์ C ++ หลักควรปล่อยอย่างน้อยคำเตือนสำหรับรหัสที่ไม่ถูกต้อง ถ้าฉันทำร่างกายของpi()ว่างเปล่า GCC / Clang จะรายงานคำเตือนและ MSVC จะรายงานข้อผิดพลาด

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


MSVC สนับสนุนการตกจากจุดสิ้นสุดของ non- voidfunction หลังจาก inline asm ทำให้ค่าในการลงทะเบียนค่าตอบแทน (x87 st0ในกรณีนี้ EAX สำหรับจำนวนเต็มและอาจเป็น xmm0 ในรูปแบบการโทรที่ส่งคืน float / double ใน xmm0 แทนที่จะเป็น st0) การกำหนดลักษณะการทำงานนี้เป็นลักษณะเฉพาะของ MSVC ไม่แม้แต่จะดังกราวด้วย-fasm-blocksการสนับสนุนไวยากรณ์เดียวกันทำให้สิ่งนี้ปลอดภัย ดูที่__asm ​​{}; คืนค่า eax หรือไม่
Peter Cordes

0

ภายใต้สถานการณ์ใดที่ไม่ได้เกิดข้อผิดพลาด หากมันประกาศประเภทส่งคืนและไม่ส่งคืนสิ่งใดสิ่งหนึ่งดูเหมือนว่าเป็นข้อผิดพลาดให้ฉัน

ข้อยกเว้นเดียวที่ฉันคิดได้ก็คือmain()ฟังก์ชั่นซึ่งไม่ต้องการreturnคำสั่งเลย (อย่างน้อยใน C ++; ฉันไม่มีมาตรฐาน C อย่างใดอย่างหนึ่งที่มีประโยชน์) หากไม่มีการคืนก็จะทำราวกับว่าreturn 0;เป็นคำสั่งสุดท้าย


1
main()ต้องการ a returnใน C.
Chris Lutz

@Jefromi: สหกรณ์ถูกถามเกี่ยวกับฟังก์ชั่นที่ไม่เป็นโมฆะโดยไม่ต้องมีreturn <value>;คำสั่ง
บิล

2
main คืนค่า 0 โดยอัตโนมัติใน C และ C ++ C89 ต้องการผลตอบแทนที่ชัดเจน
Johannes Schaub - litb

1
@Chris: ใน C99 มีนัยreturn 0;ที่ปลายmain()(และmain()เท่านั้น) แต่มันก็เป็นสไตล์ที่ดีที่จะเพิ่มreturn 0;ต่อไป
pmg

0

ดูเหมือนคุณจะต้องเปิดการเตือนคอมไพเลอร์ของคุณ:

$ gcc -Wall -Wextra -Werror -x c -
int main(void) { return; }
cc1: warnings being treated as errors
<stdin>: In function main’:
<stdin>:1: warning: return with no value, in function returning non-void
<stdin>:1: warning: control reaches end of non-void function
$

5
การพูดว่า "เปิดใช้ -Werror" นั้นไม่ใช่คำตอบ เห็นได้ชัดว่ามีความแตกต่างในความรุนแรงระหว่างปัญหาที่จัดเป็นคำเตือนและข้อผิดพลาดและ gcc ถือว่าคนนี้เป็นระดับที่รุนแรงน้อยกว่า
Cascabel

2
@Jefromi: จากมุมมองภาษาบริสุทธิ์ไม่มีความแตกต่างระหว่างคำเตือนและข้อผิดพลาด คอมไพเลอร์จะต้องออก "ข้อความที่ทำให้เกิดความไม่เข้าใจ" เท่านั้น ไม่จำเป็นต้องหยุดการคอมไพล์หรือเรียกสิ่งที่ "เอลเลอร์" และสิ่งอื่น "เตือน" มีข้อความแจ้งการวินิจฉัยหนึ่งข้อความ (หรือชนิดใด ๆ ) ขึ้นอยู่กับคุณในการตัดสินใจ
AnT

1
จากนั้นอีกครั้งปัญหาที่เป็นปัญหาทำให้ UB คอมไพเลอร์ไม่จำเป็นต้องจับ UB เลย
AnT

1
ใน 6.9.1 / 12 ใน n1256 จะมีข้อความว่า "ถ้า}} ที่ยกเลิกฟังก์ชั่นถึงและค่าของการเรียกฟังก์ชั่นถูกใช้โดยผู้โทร
Johannes Schaub - litb

2
@Chris Lutz: ฉันไม่เห็นมัน เป็นการละเมิดข้อ จำกัด ในการใช้ช่องว่างที่ชัดเจนreturn;ในฟังก์ชันที่ไม่ใช่โมฆะและเป็นการละเมิดข้อ จำกัด ที่จะใช้return <value>;ในฟังก์ชันช่องว่าง แต่ฉันเชื่อว่าไม่ใช่หัวข้อ OP อย่างที่ฉันเข้าใจมันเกี่ยวกับการออกจากฟังก์ชั่นที่ไม่เป็นโมฆะโดยไม่ต้องreturn(เพียงแค่ให้การควบคุมไหลออกจากจุดสิ้นสุดของฟังก์ชั่น) มันไม่ได้เป็นการละเมิดข้อ จำกัด AFAIK มาตรฐานเพียงแค่บอกว่ามันเป็นเสมอ UB ใน C ++ และบางครั้ง UB ใน C.
มด

-2

เป็นการละเมิดข้อ จำกัด ใน c99 แต่ไม่ใช่ใน c89 คมชัด:

c89:

3.6.6.4 The returnข้อความ

ข้อ จำกัด

คำสั่งที่มีการแสดงออกจะไม่ปรากฏในฟังก์ชั่นที่มีผลตอบแทนประเภทคือreturnvoid

c99:

6.8.6.4 returnคำแถลง

ข้อ จำกัด

คำสั่งที่มีการแสดงออกจะไม่ปรากฏในฟังก์ชั่นที่มีผลตอบแทนประเภทคือreturn คำสั่งโดยไม่แสดงออกเท่านั้นจะปรากฏในฟังก์ชั่นที่มีผลตอบแทนประเภทคือvoidreturnvoid

แม้อยู่ใน--std=c99โหมด gcc จะทำการเตือนเท่านั้น (แม้ว่าจะไม่จำเป็นต้องเปิดใช้งานการตั้ง-Wค่าสถานะเพิ่มเติมตามที่ต้องการโดยค่าเริ่มต้นหรือใน c89 / 90)

แก้ไขเพื่อเพิ่มสิ่งนั้นใน c89 "การเข้าถึง}ฟังก์ชันนั้นจะยุติลงเทียบเท่ากับการดำเนินการ areturnคำสั่งโดยไม่มีการแสดงออก" (3.6.6.4) อย่างไรก็ตามใน c99 พฤติกรรมไม่ได้กำหนด (6.9.1)


4
โปรดทราบว่านี่จะครอบคลุมเฉพาะreturnข้อความที่ชัดเจน มันไม่ครอบคลุมถึงการล้มลงในตอนท้ายของฟังก์ชั่นโดยไม่ต้องคืนค่า
John Kugelman

3
โปรดทราบว่า C99 คิดถึง "ถึง} ที่ยุติฟังก์ชั่นนั้นเทียบเท่ากับการดำเนินการข้อความสั่งคืนโดยไม่มีนิพจน์" ดังนั้นจึงไม่ได้เป็นการละเมิดข้อ จำกัด และไม่จำเป็นต้องทำการวินิจฉัย
Johannes Schaub - litb
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.