2012-01-20 52 views
18

Tôi đã đọc "C++ Cookbook" trong đó có đoạn như sau:Trộn cout và wcout trong cùng một chương trình

// cout << s << std::endl; // You shouldn't be able to 
wcout << ws << std::endl;  // run these at the same time 

Nếu bạn quan tâm đến nhìn thấy những ví dụ thực tế, đây là a link to the page on Google books.

Ngoài ra, tôi thấy điều này SO question có vẻ như là trạng thái trộn wcout và cout là không sao. Ai đó có thể giải thích cho tôi những gì bình luận này đang nói về?

EDIT

Từ C++ chuẩn [27.4.1]:

Trộn hoạt động trên tương ứng wide- và hẹp ký tự suối theo ngữ nghĩa giống như trộn các hoạt động đó trên các tập tin, theo quy định trong Sửa đổi 1 của tiêu chuẩn ISO C.

Từ C Tiêu chuẩn [7.19.2]:

Mỗi dòng có một định hướng. Sau khi một luồng được liên kết với một tệp bên ngoài, nhưng trước khi bất kỳ hoạt động nào được thực hiện trên luồng đó, luồng không có định hướng. Khi chức năng đầu vào/đầu ra của ký tự rộng được áp dụng cho luồng không có hướng, luồng sẽ trở thành luồng có định hướng rộng. Tương tự, khi hàm đầu vào/đầu ra byte có được áp dụng cho luồng không có hướng, luồng sẽ trở thành luồng định hướng byte. Chỉ có một cuộc gọi đến chức năng freopen hoặc chức năng fwide có thể thay đổi hướng của một luồng. (Gọi thành công tới freopen sẽ xóa bất kỳ hướng nào.)

Chức năng đầu vào/đầu ra không được áp dụng cho luồng định hướng rộng và chức năng đầu vào/đầu ra ký tự rộng không được áp dụng cho luồng định hướng byte.

Vì vậy, tiêu chuẩn dường như nói rằng bạn không nên trộn chúng. Tuy nhiên, tôi đã tìm thấy báo giá này from this article:

Đối với Visual C++ 10.0, chức năng fwide được ghi nhận là chưa được thực hiện. Và từ một quan điểm thực tế, ít nhất là ở mức xuất ra toàn bộ dòng nó dường như hoạt động tốt để xen kẽ việc sử dụng cout và wcout. Vì vậy, vui vẻ, Visual C++ dường như chỉ bỏ qua các yêu cầu của tiêu chuẩn và không duy trì định hướng luồng C FILE rõ ràng không thực tế.

Và cũng có thể, liên quan đến gcc tôi thấy câu nói này từ here:

Đây là một (mới) tính năng, không phải là một lỗi, xin xem libstdC++/11.705 và tìm kiếm chung về hướng suối trong Tiêu chuẩn C (C99, 7.19.2). Tóm lại, bạn không thể kết hợp các định dạng I/O được định hướng theo chiều rộng và byte. Hiện tại, do lỗi được chỉ ra trong libstdC++/11705, bạn có thể đạt được điều gì đó gần với mong đợi của mình bằng cách gọi std :: ios :: sync_with_stdio (false); ở đầu chương trình của bạn.

Trả lời

16

Khi cout hoặc wcout được gọi lần đầu tiên, hướng cho stdout sẽ được đặt. Trong trường hợp cout, stdout trở thành luồng có định hướng byte và trong trường hợp là wcout, stdout sẽ trở thành luồng có định hướng rộng. Theo tiêu chuẩn C++ [27.4.1] và tiêu chuẩn C [7.19.2], khi định hướng của một luồng được thiết lập, bạn không nên gọi một hàm không tương thích với hướng của luồng đó.

2

Tôi không biết.

Chủ đề chặn, bạn không thể chạy bất kỳ hai câu lệnh nào "cùng một lúc". Bạn chắc chắn có thể sử dụng coutwcout tại các điểm khác nhau trong chương trình của mình. Cả hai bản đồ là STDOUT và đó là ... mặc dù bạn có thể bị lỗi các bộ đệm khác nhau và nhận được thứ tự không mong muốn một chút, trong một số trường hợp.

Rõ ràng, mỗi thấm đẫm một hướng vào "điểm đến" dòng STDOUT, và nó không được phép trộn hoạt động trên một dòng suối đã được thấm nhuần với một định hướng [C++11: 27.4.1][C99: 7.19.2].

+0

Tôi thực sự đã kiểm tra trang errata của cuốn sách vì tôi nghĩ rằng đó có thể là một sai lầm, nhưng không thể tìm thấy bất cứ điều gì. –

+0

@Jesse: Thời gian để liên lạc với tác giả, có lẽ. –

+0

Bạn có thể giải thích ý của bạn và những gì thực sự xảy ra: "Cả hai đều bản đồ thành STDOUT"? , Cảm ơn –

1

Về mặt kỹ thuật, bạn chắc chắn có thể sử dụng đồng thời cả luồng hẹp và luồng rộng. Kết quả là, tuy nhiên, có khả năng được điều sai lầm, trừ khi bạn sắp xếp cho cả hai người trong số họ để mã hóa các ký tự như nhau. Điều này, thật không may, đi kèm với báo trước rằng bạn không thể kiểm soát các mã hóa được sử dụng bởi các đối tượng dòng tiêu chuẩn, ít nhất là không di chuyển được. Ngay cả khi mã hóa là như nhau, bạn cần đảm bảo rằng các ký tự một phần được viết hoàn toàn, tức là ít nhất bạn cũng cần phải xóa bộ đệm khi chuyển sang chiều rộng khác.

+0

Có phải 'imbue' không được xác định cho luồng trong tiêu chuẩn hay tôi nên giải thích điều này như thế nào? – Voo

+1

@Voo 'imbue()' thực sự ** được ** xác định cho tất cả các đối tượng luồng. Tuy nhiên, bộ đệm luồng duy nhất cần thiết để sử dụng 'std :: codecvt <...>' là 'std :: basic_filebuf <...>'. Tuy nhiên, các đối tượng dòng tiêu chuẩn không bắt buộc phải sử dụng loại bộ đệm luồng này. Họ có thể sử dụng 'std :: basic_filebuf <...>' nhưng tôi sẽ không dựa vào nó, một phần vì tôi không thể tưởng tượng rằng tôi sẽ thực hiện nó theo cách đó.Trên thực tế, tôi nên kiểm tra các tiêu chuẩn C + + 2011 cho điều này: nó chắc chắn đúng trong C + + 2003 nhưng tôi không nghĩ rằng nó đã thay đổi. –

+0

Điều đó thật thú vị - tôi chỉ sử dụng 'imbue' cho các tệp mà nó hoạt động tốt, nhưng tôi ngầm dự kiến ​​điều này sẽ làm việc cho các đối tượng luồng chuẩn. Tốt để biết - nhưng sau đó có một lý do tôi không bao giờ cần nó cho các dòng tiêu chuẩn ở nơi đầu tiên vì vậy nó có lẽ không có vấn đề lớn trong thực tế .. – Voo

1

Vi phạm "sẽ không" từ tiêu chuẩn thường đưa bạn đến phạm vi của hành vi không xác định. Hành vi không xác định có thể hoạt động tốt trên một số triển khai.

0

Giả sử: coutwcout là hai luồng khác nhau và dấu ngoặc kép bạn cung cấp không nói gì về cách định hướng luồng tương quan với hướng của tệp cơ bản. Có thể là các luồng âm thầm định hướng lại stdout dưới mui xe?

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