2012-01-20 2 views
18

Я читал «C++ Cookbook», который имел следующий фрагмент кода:Смешивание COUT и wcout в той же программе

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

Если вы заинтересованы в том, чтобы фактический пример, вот a link to the page on Google books.

Кроме того, я нашел это SO question, который, похоже, указывает, что смешивание wcout и cout в порядке. Может ли кто-нибудь объяснить мне, о чем говорит этот комментарий?

РЕДАКТИРОВАТЬ

От стандарта C++ [27.4.1]:

Смешивание операций на соответствующем широкоэкранные и узкий-символьные потоки следует той же семантике, смешивая такие операции с файлами, как указано в Поправке 1 стандарта ISO C.

От C Standard [7.19.2]:

Каждый поток имеет ориентацию. После того, как поток связан с внешним файлом, но перед выполнением каких-либо операций, поток не имеет ориентации. Как только широкая функция ввода/вывода символов применяется к потоку без ориентации, поток становится широко ориентированным потоком. Аналогично, как только функция ввода/вывода байта имеет , применяется к потоку без ориентации, поток становится потоком, ориентированным на байты. Только вызов функции freopen или функции fwide может в противном случае изменить ориентацию потока . (Успешный вызов freopen удаляет любую ориентацию.)

Байт функции ввода/вывода не применяются к широко ориентированному потоку, а широкие функции ввода/вывода символов не применяются к потоку, ориентированному на байты.

Итак, стандарт, кажется, говорит, что вы не должны смешивать их. Тем не менее, я нашел эту цитату from this article:

Для Visual C++ 10.0 функция fwide документирована как нереализованная. И с практической точки зрения, по крайней мере на уровне вывода целых строк, он, по-видимому, отлично работает, чтобы объединить использование cout и wcout. Поэтому, к счастью, Visual C++, по-видимому, просто игнорирует требования стандарта и не поддерживает непрактичную явную ориентацию потока C FILE.

А также, относительно GCC я нашел эту цитату из here:

Это (новая) особенность, а не ошибка, см libstdC++/11705 и в общем поиске об ориентации потока в C (C99, 7.19.2). В двух словах вы не можете смешивать ориентированные и широко ориентированные I/O байты. На данный момент из-за ошибки , указанной в libstdC++/11705, вы можете получить что-то близкое к ожиданиям , вызвав std :: ios :: sync_with_stdio (false); в начале вашей программы.

ответ

16

Когда cout или wcout вызывается в первый раз, ориентация на stdout будет установлена. В случае cout, stdout становится потоком, ориентированным по байтам, а в случае wcoutstdout становится широко ориентированным потоком. В соответствии со стандартом C++ [27.4.1] и стандартом C [7.19.2], как только ориентация потока установлена, вы не должны вызывать функцию, которая несовместима с ориентацией этого потока.

2

Я понятия не имею.

Запрет нитей, вы не можете запустить любые два заявления «в то же время». Конечно, вы можете использовать cout и wcout в разных точках вашей программы. Оба они сопоставляются с STDOUT, и вот что ... хотя в некоторых случаях вы можете ошибаться в разных буферах и получать слегка неожиданный порядок.

По-видимому, каждый насыщает собой ориентацию на «адресат» поток STDOUT, и это не допускается смешивать операции на потоке, который был пропитан с ориентацией [C++11: 27.4.1] и [C99: 7.19.2].

+0

Я действительно проверил страницу с ошибками книги, потому что думал, что это может быть ошибка, но ничего не нашел. –

+0

@ Джесси: Время связаться с автором, возможно. –

+0

Можете ли вы объяснить, что вы имеете в виду, и что на самом деле происходит: «Они оба сопоставляются с STDOUT»? , Спасибо –

1

Технически вы можете определенно использовать как узкие, так и широкие потоки одновременно. Однако результат, скорее всего, будет испорчен, если вы не согласитесь, чтобы оба они кодировали символы одинаково. К сожалению, это связано с тем, что вы не можете управлять кодировками, используемыми стандартными объектами потока, по крайней мере, не переносимыми. Даже если кодирование одинаковое, вам необходимо убедиться, что частичные символы полностью записаны, то есть по крайней мере вам нужно сбросить буфер при переключении на другую ширину.

+0

Является ли 'imbue' не определено для потоков в стандарте или как это следует интерпретировать? – Voo

+1

@Voo 'imbue()' фактически ** ** определено для всех объектов потока. Тем не менее, единственным буфером потока, необходимым для использования 'std :: codecvt <...>', является 'std :: basic_filebuf <...>'. Тем не менее, стандартные потоковые объекты не обязаны использовать этот тип буфера потока. Они могут использовать 'std :: basic_filebuf <...>', но я бы не стал рассчитывать на это, частично потому, что я не могу себе представить, что я буду реализовывать его таким образом.На самом деле, я должен проверить стандарт C++ 2011 для этого: он определенно был прав в C++ 2003, но я не думаю, что он изменился. –

+0

Это интересно - я всегда использовал 'imbue' для файлов, где он работал нормально, но я неявно ожидал, что это будет работать и для стандартных объектов потока. Полезно знать - но тогда есть причина, по которой я никогда не нуждался в ней для стандартных потоков в первую очередь, поэтому на практике это, вероятно, не имеет большого значения. – Voo

1

Нарушение правил «не должно» от стандарта, как правило, приводит вас в сферу неопределенного поведения. Неопределенное поведение может очень хорошо работать на некоторых реализациях.

0

Как угадывание: cout и wcout - это два разных потока, а предоставленные вами цитаты не говорят о том, как ориентация потока коррелирует с ориентацией основного файла. Может быть, потоки тихо переориентируют stdout под капот?

Смежные вопросы