2009-08-07 41 views
6
#include <stdio.h> 
#define MAXLEN 256 

int main() { 
    int n; 
    char buf[MAXLEN]; 
    while((n = read(0,buf,sizeof(buf))) != 0){ 
    printf("n: %d:",n); 
    write(1,buf,n); 
    } 
    return 1; 
} 

Đầu ra của chương trình (nơi read đầu tiên và write đầu tiên được gõ bởi người sử dụng và lặp lại bởi các thiết bị đầu cuối) là:write() để stdout và printf đầu ra không xen kẽ?

read 
read 
write 
write 
n: 5:n: 6: 

Kết quả của printf đưa ra sau khi nhấn tổ hợp phím Ctrl + D tại đầu vào tiêu chuẩn và không cùng với các lần đọc tiếp theo. Lý do tại sao điều này xảy ra?

Trả lời

18

Printf được đệm.

Bạn có thể buộc printf để 'xả' đệm của nó bằng cách sử dụng cuộc gọi fflush:

#include <stdio.h> 
#define MAXLEN 256 

int main() { 
    int n; 
    char buf[MAXLEN]; 
    while((n = read(0,buf,sizeof(buf))) != 0){ 
    printf("n: %d:",n); 
    fflush(stdout); /* force it to go out */ 
    write(1,buf,n); 
    } 
    return 1; 
} 

Nói chung, printf() được đệm là một điều tốt. Unbuffered đầu ra, đặc biệt là để bàn giao tiếp có thể nhìn thấy yêu cầu cập nhật màn hình và như vậy, là chậm. Đủ chậm rằng một ứng dụng đang in rất nhiều có thể trực tiếp bị chậm lại bởi nó (đặc biệt là trên nền tảng Windows; Linux và unixes thường bị ảnh hưởng ít hơn).

Tuy nhiên, printf() bị lưu vào bộ đệm không ảnh hưởng đến bạn nếu bạn cũng fprintf(stderr,) - stderr được cố tình bỏ chặn. Kết quả là, bạn có thể nhận được tin nhắn của bạn với một số thiếu printf(); nếu bạn viết cho một điều khiển khác là FILE cũng được liên kết với thiết bị đầu cuối và có thể bị vô hiệu hóa, hãy đảm bảo bạn rõ ràng trước tiên là fflush(stdout).

+5

Bạn cũng có thể thay đổi chế độ đệm bằng setvbuf() trước khi thực hiện bất kỳ IO nào. – AProgrammer

+0

"' printf() 'là [đệm] (http://en.wikipedia.org/wiki/Data_buffer)" nghĩa là gì? – ma11hew28

+0

http://stackoverflow.com/a/17552608/242933 – ma11hew28

1

Printf đang sử dụng stdio và bộ đệm được lưu vào bộ đệm. Đẩy nó ra bằng cách gửi thay đổi sang "n:% d: \ n"

+0

Hoặc là, hoặc không kết hợp các kênh đầu ra - tức là sử dụng một và cùng chức năng để xuất tất cả nội dung. –

+1

\ n không đảm bảo tuôn ra. – EFraim

+1

stdout là dòng đệm trừ khi nó hướng đến một thiết bị không tương tác. – AProgrammer

2

Các manpage cho fgets nói với tôi:

Nó không phải là khuyến khích để trộn các cuộc gọi đến các chức năng đầu vào từ thư viện stdio với mức độ thấp các cuộc gọi đến đọc (2) đối với mô tả tập tin associ- ated với luồng đầu vào; kết quả sẽ không xác định và rất có thể không phải là những gì bạn muốn.

Vì vậy, giải pháp tốt nhất sẽ không được sử dụng viết và printf trên cùng một bộ mô tả.

+0

POSIX chỉ định rất cẩn thận khi kết quả không xác định và khi chúng được xác định rõ dựa trên khái niệm trừu tượng của "xử lý hoạt động". Xem http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_05_01 –

0

Sử dụng fwrite (phiên bản luồng) thay vì viết.

Lưu ý rằng, trong khi được liên kết với tệp số 1, nó không giống nhau.

1

Bạn có thể sử dụng hàm std fflush() để xóa bộ đệm ra hoặc bạn có thể sử dụng thêm \ n ở cuối chuỗi điều khiển bên trong printf. Một cái gì đó như thế này

printf("\n :%d:\n",n); 

của nó luôn luôn tốt hơn để sử dụng write() chức năng & read() trong C thay vì printf() và scanf(). Printf và scanf có một số vấn đề như printf lưu trữ tham số chuỗi trong bộ đệm stdout. Vì vậy, cần phải thực hiện xả bằng tay thông qua chức năng fflush hoặc bằng phương tiện \ n. Trong một chương trình in hello thế giới nhỏ, bạn sẽ không tìm thấy một vấn đề như bộ đệm stdout được flushed ở phần cuối của chương trình thực hiện. Sử dụng tốt hơn write() hoạt động tốt. scanf cũng có vấn đề về không gian đọc và rất nhiều vấn đề khác liên quan đến bộ đệm stdin.

Ví dụ trong các mã dưới đây:

main() { char a; int i=0,c; for(;i<2;i++) { scanf("%d",&c); scanf("%c",&a);} } 

Các chương trình trên như có vấn đề về đọc \ n vào stdin trên nhấn Enter. Chúng tôi có thể giải quyết vấn đề này nhưng không xóa bộ đệm stdin hoặc sử dụng ký tự \ n. Luôn luôn tốt hơn để sử dụng các hàm read() và write().

Hy vọng rằng sẽ giúp ....

Các vấn đề liên quan