Какая разница между printf ( "% s" ), printf ( "% ls" ), wprintf ( "% s" ) и wprintf ( "% ls" )?
Рассмотрим эту примерную программу:
#include <cstdio>
#include <cwchar>
#include <string>
int main()
{
std::string narrowstr = "narrow";
std::wstring widestr = L"wide";
printf("1 %s \n", narrowstr.c_str());
printf("2 %ls \n", widestr.c_str());
wprintf(L"3 %s \n", narrowstr.c_str());
wprintf(L"4 %ls \n", widestr.c_str());
return 0;
}
Результат этого:
1 narrow
2 wide
Мне интересно:
- почему 3 и 4 не печатали
- какие различия между 1 и 3 и 2 и 4.
- Не имеет значения, если узкий str находится в utf8, а widestr - в utf16?
Ответы
Ответ 1
Вам нужно сделать:
wprintf(L"3 %hs \n", narrowstr.c_str());
wprintf(L"4 %s \n", widestr.c_str());
Почему? Потому что для printf
, % s говорит узкий char -string. Для wprintf
, % ls говорит широко.
Но для wprintf
% s подразумевается широкий, % ls будет означать широту. % hs будет означать узкий (для обоих). Для printf
, % s, таким образом будет просто означать % hs
В VС++/Windows, %S
(capital S), будет отменено действие. Для printf("%S")
это будет означать широкое, а wprintf("%S")
будет означать узкий. Это полезно для _tprintf
.
Ответ 2
Обратите внимание, что вы используете потоки C. C-потоки имеют очень особое качество, называемое "ориентация". Поток является либо неориентированным, либо широким, либо узким. Ориентация определяется первым выходом, сделанным для любого конкретного потока (см. http://en.cppreference.com/w/cpp/io/c для сводки потоков C I/O)
В вашем случае stdout
запускается неориентированным, и, выполняя первый printf
, вы устанавливаете его узким. После того, как он узкий, он застрял, и wprintf
не удается (проверьте его код возврата!). Единственный способ изменить поток C - это freopen
он, который не работает с stdout. Вот почему 3 и 4 не печатались.
Различия между 1 и 3 заключаются в том, что 1 является узкой выходной функцией, которая использует спецификатор узких строк% s: он считывает байты из массива char и отправляет байты в поток байтов. 3 - широкая функция вывода с узким указателем преобразования строк% s: сначала он считывает байты из массива char и mbtowc
их в wchar_t
s, а затем отправляет wchar_t
в широкий поток, который затем wctomb
их в байты или многобайтовые последовательности, которые затем вставляются в стандартную версию с помощью write
Наконец, если widestr находится в utf16, вы должны использовать Windows, и все ставки отключены; поддержка ASCII на этой платформе очень мало. Вы можете также использовать WinAPI и использовать его с помощью стандартного С++ 11 для некоторых вещей в Unicode и даже делать этот вывод C с волшебными словами _setmode(_fileno(stdout), _O_U16TEXT);
, которые обсуждались достаточно часто)
Ответ 3
Ответы на вопросы 1 и 2 находятся в документации. Любой хороший набор документации будет делать. Говорят, cppreference очень хорошо.
Как и в случае с 3, в стандарте языка не указывается какая-либо конкретная кодировка для строк или какой-либо конкретный размер wchar_t
. Вам нужно проконсультироваться с документацией для вашей реализации, а не для собственно языка (хотя писать код, зависящий от реализации, редко бывает целесообразным).