// sample-utf8-bom.cpp: non-ASCII text in a source file saved as UTF-8 // WITH a byte order mark (the bytes EF BB BF before these comments). // Free sample from 99helpers.com/file-types/cpp // // Why the BOM matters: GCC and Clang read source as UTF-8 either way, but // Microsoft's compiler reads a file without a BOM in the system code page, // unless you pass /utf-8. With the BOM, MSVC knows the file is UTF-8. // c++ -Wall -Wextra -std=c++20 sample-utf8-bom.cpp -o sample-utf8 && ./sample-utf8 // cl /W4 /EHsc /std:c++20 sample-utf8-bom.cpp // (/utf-8 is still worth adding on MSVC: it also makes the program's // strings UTF-8, whatever the system code page. On Windows, run // `chcp 65001` first so the console shows UTF-8 output.) #include #include #include #include // In C++20, u8"..." literals have their own character type, char8_t, which // iostreams can't print directly. Plain "..." literals in a UTF-8 file stay // char, which is why this program uses them. static_assert(std::is_same_v); // std::string_view::size() counts bytes, like strlen. Counting the bytes // that don't start with the bits 10 counts code points instead. constexpr std::size_t code_points(std::string_view text) { std::size_t n = 0; for (unsigned char c : text) { if ((c & 0xC0) != 0x80) { ++n; } } return n; } int main() { constexpr std::string_view greetings[] = { "Hello", "Grüß Gott", "Bonjour, ça va ?", "Привет", "Γειά σου", "שלום", "مرحبا", "こんにちは", "你好", "👋🙂", }; static_assert(code_points("こんにちは") == 5); for (auto text : greetings) { std::cout << text.size() << " bytes, " << code_points(text) << " code points: " << text << '\n'; } }