2016-09-16 17 views
5

Tôi chỉ tò mò về điều kiện nào cần được thỏa mãn để tự động xóa bộ đệm stdout.Các quy tắc của bộ đệm stdout xả tự động trong C là gì?

Trước hết tôi đã nhầm lẫn rằng mã giả này không in ra mỗi lần lặp:

while (1) { 
    printf("Any text"); 
    sleep(1); 
} 

Nhưng nếu tôi thêm ký tự xuống dòng nó sẽ.

Sau vài thí nghiệm tôi thấy rằng trên stdout máy tính của tôi đệm là đỏ ửng:

  1. Khi tôi đưa vào stdout 1025 ký tự trở lên;
  2. Khi tôi đọc stdin;
  3. Khi tôi đặt ký tự dòng mới vào giá trị xuất chuẩn;

Điều kiện đầu tiên là hoàn toàn rõ ràng - khi bộ đệm đầy, nó phải được xả. Cái thứ hai cũng hợp lý. Nhưng tại sao ký tự dòng mới gây ra đỏ bừng? Những điều kiện tiềm ẩn khác cho điều này là gì?

+0

Gần đây tôi đã được thông báo (bởi @chux) rằng điều kiện thứ ba không có trong tiêu chuẩn C, nhưng được thực hiện được xác định, như là hai đầu tiên. –

+0

Bạn có thể xem [http://stackoverflow.com/questions/13932932/why-does-stdout-need-explicit-flushing-when-redirected-to-file#13933741](http://stackoverflow.com/questions/13932932/why-does-stdout-need-clear-flushing-khi-chuyển hướng-to-file # 13933741) – owacoder

+0

@WeatherVane: Tôi nghĩ rằng bạn hiểu lầm. Hành vi * được yêu cầu * bởi C đối với các luồng đầu ra có dòng đệm, nhưng stdout không cần phải được xếp hàng đệm trừ khi nó là một thiết bị tương tác. –

Trả lời

6

Quy tắc đệm đệm tự động xả đệm là được xác định thực hiện (ID). Đó là ID khi luồng là không bị chặn, được đệm đầy đủ hoặc dòng đệm.

Khi một luồng là không bị chặn, các ký tự được dự định xuất hiện từ nguồn hoặc tại đích càng sớm càng tốt. Nếu không, các ký tự có thể được tích lũy và truyền đến hoặc từ môi trường máy chủ dưới dạng một khối.

Khi một luồng là được đệm đầy đủ, các ký tự được dự định truyền đến hoặc từ môi trường máy chủ dưới dạng khối khi bộ đệm được lấp đầy.

Khi một luồng là dòng đệm, các ký tự được dự định truyền đến hoặc từ môi trường máy chủ dưới dạng một khối khi gặp phải một ký tự dòng mới. Hơn nữa, các ký tự được dự định truyền như một khối cho môi trường máy chủ khi một bộ đệm được lấp đầy, khi đầu vào được yêu cầu trên luồng không bị chặn hoặc khi đầu vào được yêu cầu trên luồng đệm được yêu cầu truyền các ký tự từ môi trường máy chủ .

Hỗ trợ cho những đặc điểm này là thực hiện xác định ... C11dr §7.21.3 3


Tôi chỉ tò mò mà điều kiện nên được hài lòng để tuôn đệm stdout tự động .

Nếu mã muốn đảm bảo đầu ra chắc chắn bị xóa, hãy sử dụng fflush(). Các điều kiện khác có thể tự động tuôn ra luồng được thực hiện xác định.

3
  • Luồng đầu ra được xếp hàng đệm phải được xóa khi có dòng mới.

  • Việc triển khai có thể (nhưng không bắt buộc phải) tuôn ra tất cả luồng đầu ra được lưu vào bộ đệm bất cứ khi nào đọc được cố gắng từ bất kỳ luồng đầu vào được xếp theo dòng nào.

  • Việc triển khai không được phép tạo luồng được đệm hoàn toàn theo mặc định trừ khi có thể xác định rằng chúng không được liên kết với "thiết bị tương tác". Vì vậy, khi stdin/stdout là các thiết bị đầu cuối, chúng không thể được đệm đầy đủ, chỉ có dòng đệm (hoặc không bị chặn).

Nếu bạn chỉ cần xả khi đầu ra là một thiết bị đầu cuối, nó đủ cho rằng viết một dòng mới dẫn đến xả. Nếu không, bạn nên gọi một cách rõ ràng fflush bất cứ nơi nào bạn cần xả.

+0

Cảm ơn bạn. Điều này làm rõ rất nhiều. –

3

Xem the man page for setbuf(3). Theo mặc định, stdout được đặt thành chế độ đệm dòng.

printf() và các biến thể của nó hoạt động với đầu ra được lưu vào bộ đệm và ủy quyền cho write(). Vì vậy, bộ đệm này được kiểm soát bởi việc thực hiện thư viện C là printf, với cài đặt bộ đệm và bộ đệm nằm trong cấu trúc FILE.

Cũng đáng chú ý sự khác biệt giữa phần 3 và phần 2 của trang unix man. Phần 2 được tạo thành từ các cuộc gọi hàm trực tiếp nói chuyện với hệ điều hành và làm những việc mà nếu không nó sẽ không thể thực hiện được từ một chương trình người dùng thuần túy. Phần 3 được tạo thành từ các cuộc gọi chức năng mà người dùng có thể tự tái tạo, thường được ủy quyền cho các cuộc gọi phần 2. Các hàm phần 2 chứa "phép thuật" cấp thấp cho phép các chương trình C tương tác với thế giới bên ngoài và thực hiện I/O. Các chức năng của phần 3 có thể cung cấp một giao diện thuận tiện hơn cho các chức năng của phần 2.

printf, scanf, getchar, fputs, và khác FILE * chức năng tất cả đều phần 3 chức năng mà đại biểu để write()read(), đó là phần 2 chức năng.read()write() không được đệm. printf() tương tác với bộ đệm trong cấu trúc FILE và đôi khi quyết định gửi nội dung của bộ đệm đó qua write().

+1

Cảm ơn bạn. Đó là thực sự hữu ích. Tôi không biết về những loại bộ đệm khác nhau.Và trang người đàn ông này giải thích mọi thứ. –

+0

Tôi đã viết một câu trả lời ngắn sau đó chỉnh sửa chi tiết hơn, trong trường hợp bạn đã bỏ lỡ nó. – NovaDenizen

+0

Oh yeah, tôi đã thấy nó chỉ sau bình luận của bạn :) Nhưng dù sao, liên kết đó là thông tin hữu ích nhất về điều này đối với tôi. Tôi biết về sự khác biệt giữa những phần người đàn ông, nhưng có lẽ nó sẽ hữu ích cho người khác. Cảm ơn. –

1

Có rất nhiều tình huống khi sản lượng đệm trên một dòng suối đang đỏ mặt tự động:

  1. Khi bạn cố gắng làm sản lượng và bộ đệm đầu ra đầy.
  2. Khi luồng được đóng.
  3. Khi chương trình chấm dứt bằng cách gọi thoát.
  4. Khi dòng mới được viết, nếu luồng là dòng đệm.
  5. Bất cứ khi nào một thao tác nhập trên bất kỳ luồng nào thực sự đọc dữ liệu từ tệp của nó.

stdout là dòng được đệm theo mặc định.

Nếu bạn muốn xóa đầu ra đã lưu vào lúc khác, Bạn có thể gọi fflush.

0

Online C2011 standard

7.21.3 tập tin
...
        Khi một dòng suối là unbuffered, nhân vật được dùng để xuất hiện từ nguồn hoặc tại điểm đến sớm nhất có thể. Nếu không, các ký tự có thể được tích lũy và được truyền đến hoặc từ môi trường máy chủ dưới dạng một khối. Khi một luồng là được đệm đầy đủ, ký tự được dự định truyền đến hoặc từ môi trường máy chủ dưới dạng khối khi bộ đệm được lấp đầy. Khi một luồng là dòng đệm, các ký tự được dự định là được truyền đến hoặc từ môi trường máy chủ dưới dạng một khối khi một ký tự dòng mới là gặp phải. Hơn nữa, các ký tự được dự định truyền dưới dạng khối tới môi trường máy chủ lưu trữ khi bộ đệm được điền, khi yêu cầu đầu vào trên luồng không được lọc hoặc khi yêu cầu đầu vào trên luồng được lưu vào bộ đệm yêu cầu truyền ký tự từ môi trường máy chủ. Hỗ trợ cho các đặc điểm này là được xác định thực hiện và có thể bị ảnh hưởng thông qua các chức năng setbufsetvbuf.
...
        Lúc khởi động chương trình, ba dòng văn bản được xác định trước và không cần phải được mở ra một cách rõ ràng — đầu vào tiêu chuẩn (để đọc đầu vào thông thường), chuẩn đầu ra (đối với văn bản thông thường đầu ra) và lỗi chuẩn (để viết đầu ra chẩn đoán). Khi ban đầu mở, luồng lỗi chuẩn không được đệm đầy đủ; đầu vào tiêu chuẩn và tiêu chuẩn luồng đầu ra được đệm hoàn toàn nếu và chỉ khi luồng có thể được xác định không tham chiếu cho thiết bị tương tác.

Vì vậy, luồng bộ đệm dòng sẽ tuôn ra trên dòng mới. Trên hầu hết các hệ thống tôi có kinh nghiệm, stdout là dòng đệm trong một phiên tương tác.

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