2012-07-10 18 views
9

Trong trường hợp thông thường open() trả về bộ mô tả tệp mới hoặc -1 nếu xảy ra lỗi và trong trường hợp đó, errno được đặt thích hợp.tại sao fopen() hoặc mở() sử dụng errno thay vì chỉ trả lại mã lỗi?

Tôi không hiểu tại sao cơ chế này của errno được sử dụng ở đây? mục đích ở đây là gì? tại sao chúng ta không thể lập bản đồ tất cả các lỗi với một số trả về tiêu cực không?

như

fd = open("/dev/tty0", O_RDWR | O_SYNC); 
if(fd == -1) 
    printf("this is EACCES error"); 
else if (fd == -2) 
    printf("this is EPERM error"); 

Có benifit của errno cơ chế.? nếu có thì tôi muốn biết/hiểu sau đó trong những thứ khác tôi cũng có thể sử dụng cơ chế này.

Trả lời

11

Kể từ fopen lợi nhuận một FILE* bạn không thể mong đợi nó trả về mã lỗi trong con trỏ đó: giá trị "đặc biệt" duy nhất cho con trỏ là 0.

Khi bạn quan sát, đối với open hạn chế này không giữ. Trong thực tế, hệ thống như Linux làm chính xác những gì bạn đề xuất ở cấp độ thấp hơn của họ. Hệ thống gọi dưới mui xe trả về mã lỗi tiêu cực nếu mọi thứ đi sai. Sau đó, mã (phủ định) đó được cắm vào errno bằng trình bao bọc không gian người dùng nông, sau đó trả về -1 để cho biết lỗi của ứng dụng.

Lý do điều này được thực hiện nên hoàn toàn là lịch sử.Trong thời gian tốt đẹp cũ không có luồng và errno vẫn chỉ là một biến toàn cầu đơn giản. Vào thời điểm đó, chiến lược được chọn không phát sinh nhiều chi phí và có lẽ dường như là một cách chấp nhận được để giao tiếp giữa hệ điều hành và ứng dụng. Vì các giao diện như vậy về cơ bản không thể thay đổi mà không vi phạm nhiều mã, chúng ta sẽ bị mắc kẹt với errno làm biến giả là luồng cục bộ.

Đây không phải là lý tưởng, nhưng chi phí không phải là xấu như nó âm thanh, vì đây là rõ ràng lỗi chỉ nên xảy ra chỉ đặc biệt.

+0

+1 câu trả lời rất hay –

1

errno là mã lỗi. Điều quan trọng là lập bản đồ các lỗi cho những gì đang thực sự xảy ra để bạn có thể đưa ra quyết định chiến lược trong mã của bạn về những việc cần làm tiếp theo. Ví dụ: ERANGE được xác định trong errno.h, sẽ cho bạn biết rằng kết quả của strtol("0xfffffffff",NULL,0) nằm ngoài phạm vi chức năng đó. Quan trọng hơn trong ví dụ của bạn, bạn nên biết liệu mình có lỗi EACCES hoặc EPERM để biết cách xử lý tệp hay không.

Bạn không thể ánh xạ tất cả các vấn đề với một mã lỗi vì bạn có thể gặp nhiều sự cố mà bạn muốn nắm bắt và xử lý. Khi tôi nói bắt, tôi không có nghĩa là thử/bắt.

Việc sử dụng thiết lập errno và cơ chế xử lý lỗi để bạn có thêm thông tin hơn chỉ là -1.

ERANGE, EACCES, EPERM và các loại khác được coi là macro ánh xạ tới một số lỗi cụ thể cho mục đích tiện lợi.

9

Đối với tôi Ưu điểm là nhận được thông tin lỗi được thống nhất theo cách đó, quay trở lại một số giá trị âm sẽ làm việc OK với open vì nó trả về một số nguyên, nhưng fopen trả về một FILE * nên kỹ thuật khác sẽ phải được sử dụng ở đó.

+0

TẬP_TIN * vẫn là con trỏ đến một số bộ đệm/bộ nhớ sao cho sẽ không bao giờ bị âm nên nếu xảy ra lỗi thì chúng tôi không trả về FILE * có giá trị âm? bởi vì NULL là 0 –

+6

Một con trỏ có - ít nhất là trên kiến ​​trúc mà tôi biết - không có khái niệm về sự ký kết, nó có thể (về mặt lý thuyết) bao trùm toàn bộ phạm vi của "số nguyên không dấu cơ bản" (tức là một điểm 32 bit có thể đi từ 0x00000000 đến 0xffffffff) . Và 'NULL' là chỉ và chỉ dẫn để nói" hey, điều này không thành công, nhìn vào errno để xem những gì đã đi sai " – fvu

+0

Về lý thuyết một tập hợp con trỏ dành riêng có thể được sử dụng quá; tất cả những gì cần thiết là 'char err_ptrs [MAX_ERRNO]; void * EACCESS_ptr = err_ptrs + EACCESS; 'vv để làm cho' EACCESS_ptr' một mã lỗi "hợp lệ" cho con trỏ. Tuy nhiên, phải sao chép chúng như là số nguyên và con trỏ, và thực tế là một số giao diện sử dụng toàn bộ không gian của các giá trị số nguyên như trả về hợp lệ, vẫn làm cho errno đáng giá. –

1

Cho mỗi hàm một tập hợp giá trị trả về riêng biệt làm cho việc viết mã theo kiểu chung trở nên quá phức tạp. Với ngữ nghĩa hiện tại, bạn có thể áp dụng một mô hình phổ quát:

int fd; 
if ((fd = some_function(arg1, arg2)) == -1) 
{ 
    perror("some_function"); 
    exit(1); 
} 

Bạn thậm chí có thể bọc này trong một macro:

#define CALL_OR_DIE(function, ret, ...)  \ 
    if ((ret = function(__VA_ARGS__)) == -1) \ 
    { perror(#function); exit(1); } 

Cách sử dụng:

int fd; 
CALL_OR_DIE(open, fd, "/dev/tty0", O_RDWR | O_SYNC); 
+1

Vì vậy, về cơ bản bạn đang nói (1) tốt hơn để viết '== -1' hơn' <0' (với errnos được định nghĩa là âm), và (2) đây là động lực cho 'errno'? Tôi cho rằng có một lợi ích trong việc không phải chuyển 'fd' thành' perror' trong trường hợp thất bại, bởi vì nó có thể được đọc từ 'errno' cục bộ, nhưng tôi không nghĩ nó giải thích lý do tại sao errno isn cũng không trở về từ 'mở'. –