Thư viện C không được đặt errno
thành 0 vì lý do lịch sử 1 . POSIX không còn tuyên bố các thư viện của mình sẽ không thay đổi giá trị trong trường hợp thành công và trang người dùng Linux mớierrno.h
phản ánh điều này:
Tệp <errno.h>
tiêu đề xác định biến số nguyên errno
, được đặt bởi các lệnh gọi hệ thống và một số hàm thư viện trong trường hợp có lỗi để chỉ ra lỗi sai. Giá trị của nó chỉ có ý nghĩa khi giá trị trả về của cuộc gọi chỉ ra lỗi (nghĩa là -1
từ hầu hết các cuộc gọi hệ thống; -1
hoặc NULL
từ hầu hết các chức năng của thư viện); một chức năng thành công được phép thay đổi errno
.
Cơ sở lý luận ANSI C tuyên bố rằng ủy ban cảm thấy thực tế hơn khi áp dụng và tiêu chuẩn hóa việc sử dụng hiện có errno
.
Các máy móc báo cáo lỗi tập trung vào cài đặt errno
thường được coi là có khả năng chịu đựng tốt nhất. Nó đòi hỏi một `` khớp nối bệnh lý '' giữa các chức năng của thư viện và sử dụng một ô nhớ có thể ghi tĩnh, gây cản trở việc xây dựng các thư viện có thể chia sẻ. Tuy nhiên, Ủy ban ưu tiên tiêu chuẩn hóa máy móc hiện có, tuy nhiên thiếu này hơn là phát minh ra thứ gì đó tham vọng hơn.
Hầu như luôn luôn có một cách để kiểm tra lỗi ngoài việc kiểm tra nếu errno
đã được đặt. Kiểm tra nếu errno
đã đặt không phải lúc nào cũng đáng tin cậy, vì một số cuộc gọi yêu cầu gọi API riêng để nhận lý do lỗi. Chẳng hạn, ferror()
được sử dụng để kiểm tra lỗi nếu bạn nhận được kết quả ngắn từ fread()
hoặc fwrite()
.
Thật thú vị, ví dụ về việc sử dụng của bạn strtod()
là một trong những trường hợp cài đặt errno
thành 0 trước khi cuộc gọi được yêu cầu để phát hiện chính xác nếu xảy ra lỗi. Tất cả các hàm strto*()
chuỗi đến số đều có yêu cầu này, bởi vì giá trị trả về hợp lệ được trả về ngay cả khi gặp lỗi.
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? */
}
}
Đoạn mã trên dựa trên hành vi strtod()
như được ghi lại trên Linux . Tiêu chuẩn C chỉ quy định rằng dòng chảy bên dưới không thể trả về giá trị lớn hơn giá trị dương nhỏ nhất double
và việc có errno
được đặt thành hay không ERANGE
được thực hiện được xác định 2 .
Trên thực tế, có một bài viết tư vấn chứng nhận mở rộng khuyến nghị luôn luôn đặt errno
thành 0 trước khi gọi thư viện và kiểm tra giá trị của nó sau khi cuộc gọi cho biết đã xảy ra lỗi . Điều này là do một số cuộc gọi thư viện sẽ được đặt errno
ngay cả khi cuộc gọi đó đã thành công 3 .
Giá trị errno
là 0 khi khởi động chương trình, nhưng nó không bao giờ được đặt thành 0 bởi bất kỳ chức năng thư viện nào. Giá trị của errno
có thể được đặt thành khác không bằng lệnh gọi hàm thư viện cho dù có lỗi hay không, miễn là việc sử dụng errno
không được ghi lại trong phần mô tả chức năng trong Tiêu chuẩn C. Nó có ý nghĩa đối với một chương trình kiểm tra nội dung errno
chỉ sau khi một lỗi được báo cáo. Chính xác hơn, errno
chỉ có ý nghĩa sau khi hàm thư viện đặt errno
lỗi đã trả về mã lỗi.
1. Trước đây tôi đã tuyên bố rằng đó là để tránh che giấu lỗi từ một cuộc gọi trước đó. Tôi không thể tìm thấy bất kỳ bằng chứng nào để hỗ trợ cho tuyên bố này. Tôi cũng đã có một printf()
ví dụ không có thật .
2. Cảm ơn @chux đã chỉ ra điều này. Tham chiếu là C.11 §7.22.1.3 10.
3. Được chỉ ra bởi @KeithThndry trong một bình luận.
errno
, bạn luôn có thể tự đặt nó về 0.