ห้องสมุด C ไม่ได้ตั้งค่าerrnoเป็น 0 เพื่อเหตุผลทางประวัติศาสตร์1 POSIX ไม่อ้างว่าห้องสมุดจะไม่เปลี่ยนค่าในกรณีที่ประสบความสำเร็จอีกต่อไปและหน้าลินุกซ์ใหม่สำหรับการerrno.hสะท้อนสิ่งนี้:
<errno.h>ไฟล์ส่วนหัวกำหนดตัวแปรจำนวนเต็มerrnoซึ่งถูกกำหนดโดยสายระบบและบางฟังก์ชั่นห้องสมุดในกรณีที่มีข้อผิดพลาดในการบ่งบอกถึงสิ่งที่ผิดไป ค่าของมันมีความสำคัญเฉพาะเมื่อค่าส่งคืนของการโทรระบุข้อผิดพลาด (เช่น-1จากการเรียกของระบบส่วนใหญ่-1หรือNULLจากฟังก์ชั่นห้องสมุดส่วนใหญ่); ฟังก์ชั่นที่ประสบความสำเร็จจะerrnoได้รับอนุญาตให้มีการเปลี่ยนแปลง
ANSI C เหตุผลerrnoระบุว่าคณะกรรมการรู้สึกว่ามันเป็นจริงมากขึ้นเพื่อนำมาใช้และมาตรฐานการปฏิบัติที่มีอยู่ของการใช้
เครื่องจักรการรายงานข้อผิดพลาดที่มีศูนย์กลางเกี่ยวกับการตั้งค่าerrnoนั้นโดยทั่วไปถือว่ามีความอดทนที่ดีที่สุด มันต้องใช้ `` พยาธิวิทยาการเชื่อมต่อ '' ระหว่างฟังก์ชั่นห้องสมุดและใช้ประโยชน์จากเซลล์หน่วยความจำแบบเขียนได้แบบสแตติกซึ่งรบกวนการสร้างไลบรารีแบบแบ่งใช้ อย่างไรก็ตามคณะกรรมการมีความประสงค์ที่จะสร้างมาตรฐานที่มีอยู่ในปัจจุบัน แต่มีข้อบกพร่องเครื่องจักรมากกว่าที่จะคิดค้นสิ่งที่มีความทะเยอทะยานมากขึ้น
มีวิธีการตรวจสอบข้อผิดพลาดนอกเหนือจากการตรวจสอบเกือบทุกครั้งหากerrnoตั้งค่าไว้ การตรวจสอบว่าerrnoชุดที่ตั้งไว้ไม่น่าเชื่อถือเสมอไปหรือไม่เนื่องจากการโทรบางครั้งจำเป็นต้องเรียก API แยกต่างหากเพื่อรับเหตุผลข้อผิดพลาด ยกตัวอย่างเช่นferror()จะใช้ในการตรวจสอบข้อผิดพลาดถ้าคุณได้รับผลระยะสั้น ๆ จากหรือfread()fwrite()
ที่น่าสนใจพอตัวอย่างของคุณของการใช้strtod()เป็นหนึ่งในกรณีที่การตั้งค่าerrnoให้เป็น 0 ก่อนที่สายจะต้องให้ถูกต้องตรวจสอบได้หากมีข้อผิดพลาดเกิดขึ้น ทั้งหมดstrto*()สตริงฟังก์ชั่นมีความต้องการจำนวนนี้เพราะค่าตอบแทนที่ถูกต้องจะถูกส่งกลับแม้ในใบหน้าของข้อผิดพลาด
errno = 0;
char *endptr;
double x = strtod(str1, &endptr);
if (endptr == str1) {
/*...parse error */
} else if (errno == ERANGE) {
if (x == 0) {
/*...underflow */
} else if (x == HUGE_VAL) {
/*...positive overflow */
} else if (x == -HUGE_VAL) {
/*...negative overflow */
} else {
/*...unknown range error? */
}
}
รหัสดังกล่าวจะขึ้นอยู่กับลักษณะการทำงานของstrtod()การบันทึกไว้บน Linux มาตรฐาน C เท่านั้นกำหนดว่า underflow ไม่สามารถกลับมากขึ้นคุ้มค่ากว่าในเชิงบวกที่เล็กที่สุดdoubleและไม่ว่าจะได้หรือไม่errnoถูกตั้งค่าให้ERANGEมีการดำเนินงานที่กำหนดไว้2
มีจริงกว้างขวางCERT Advisory เขียนขึ้นที่แนะนำเสมอการตั้งค่าerrnoให้เป็น 0 ก่อนที่จะโทรห้องสมุดและการตรวจสอบความคุ้มค่าหลังจากที่โทรแสดงให้เห็นความล้มเหลวที่เกิดขึ้น เพราะนี่คือบางสายห้องสมุดจะตั้งerrnoแม้ว่าการเรียกตัวเองประสบความสำเร็จ3
ค่าerrnoเป็น 0 เมื่อเริ่มต้นโปรแกรม แต่ไม่เคยถูกตั้งค่าเป็น 0 โดยฟังก์ชันไลบรารีใด ๆ ค่าของerrnoอาจถูกตั้งค่าเป็นไม่ใช่ศูนย์โดยการเรียกฟังก์ชันไลบรารีว่ามีข้อผิดพลาดหรือไม่หากการใช้งานerrnoไม่ได้บันทึกไว้ในคำอธิบายของฟังก์ชันใน C Standard มันมีความหมายสำหรับโปรแกรมที่จะตรวจสอบเนื้อหาerrnoหลังจากที่รายงานข้อผิดพลาดแล้วเท่านั้น แม่นยำยิ่งขึ้นerrnoมีความหมายเฉพาะหลังจากฟังก์ชันไลบรารีที่ตั้งค่าความerrnoผิดพลาดได้ส่งคืนรหัสข้อผิดพลาด
1. ก่อนหน้านี้ฉันอ้างว่าเพื่อหลีกเลี่ยงการปิดบังข้อผิดพลาดจากการโทรก่อนหน้านี้ ฉันไม่พบหลักฐานใด ๆ ที่สนับสนุนข้อเรียกร้องนี้ ฉันยังมีprintf()ตัวอย่างปลอม
2. ขอบคุณ @chux ที่ชี้เรื่องนี้ออกมา การอ้างอิงคือ C.11 §7.22.1.3¶10
3. ชี้โดย @KeithThompson ในความคิดเห็น
errnoคุณสามารถตั้งค่าให้เป็นศูนย์ด้วยตัวเอง