Не смотря на то, что в мире Linux-ов уже давным давно все на UTF-8, под Windows еще встречаются исходники с комментариями и не-юникодными строковыми/символьными литералами в CP1251. При этом Microsoft добавила в свой компилятор ключик -execution-charset, который указывает, в каком представлении строковые константы будут представлены в результирующем exe/dll файле. Соответственно, значение utf-8 для -execution-charset указывает, что в run-time ваши narrow string-и будут на самом деле в Unicode, в UTF-8 представлении. Как в Linux-е.
Но, если у вас narrow string литералы в исходнике в CP1251, то компилятору нужно указать это, чтобы он правильно сделал их конверсию в UTF-8. Для чего предназначен ключик -source-charset и значение windows-1251 для него.
Однако, указав VC++ компилятору и -source-charset:windows-1251, и -execution-charset:utf-8, можно сделать для себя удивительные открытия.
Вот, например, простая программа:
#include <iostream> #include <typeinfo> int main() { const char str[]{ "Привет!" }; std::cout << sizeof(str) << std::endl; } |
Когда мы ее компилируем только с -source-charset:windows-1251, то результат 8. Что вполне ожидаемо, т.к. в слове "Привет" шесть букв, плюс восклицательный знак, плюс финальный ноль-символ.
Но если мы добавим ключик -execution-charset:utf-8, то результатом будет уже 14.
Почему? Потому что каждый русский символ будет представлен уже двумя байтами в UTF-8, плюс восклицательный знак, плюс ноль-символ.
Но еще интереснее, если мы попытаемся задать массив char-ов посимвольно. Что-то вроде:
const char s[]{ 'П', 'р', 'и', 'в', 'е', 'т'};
Тут мы получим предупреждение компилятора об усечении значения при приведении его к типу char.
Но откуда это самое усечение возьмется?
А давайте посмотрим на это с помощью другой простенькой программы:
#include <iostream> #include <typeinfo> template<typename T> char to_char(T v) noexcept { using TU = std::make_unsigned_t<T>; std::cout << "type is: " << typeid(T).name() << ", value: 0x" << std::hex << static_cast<unsigned>(static_cast<TU>(v)) << std::dec << std::endl; return static_cast<char>(v); } void dump_hex(const std::string & w) { std::cout << std::hex; for(const auto ch : w) std::cout << "0x" << static_cast<unsigned>(static_cast<unsigned char>(ch)) << ", "; std::cout << std::dec << std::endl; } int main() { to_char( 'П' ); dump_hex( "П" ); } |
Если мы скомпилируем ее только с ключиком -source-charset:windows-1251, то получим:
type is: char, value: 0xcf
0xcf,
Т.е. вполне ожидаемо символьный литерал у нас имеет тип char.
А если добавим -execution-charset:utf-8, то:
type is: int, value: 0xd09f
0xd0, 0x9f,
Оказывается, что у символьного литерала уже тип int.
Что, в принципе, понятно. Но оказалось неожиданно :)
На правах саморекламы: изобретаю велосипеды для себя, могу изобретать и для вас.