The C++20’s u8/char8_t Backward-Compatibility Fiasco

There is a myth according to which every new C++ version is backward compatible with the older versions. While there is a common general trend to try and keep backward compatibility across different C++ versions, that’s not always the case.

A “recent” example is provided by C++20’s u8 and char8_t.

Consider the following C++ code snippet:

// This function takes a UTF-8 string as input,
// and does something with it.
void DoSomething(const char* utf8Text);

...

int main()
{
    // A UTF-8 string literal
    auto s = u8"Connie plus some UTF-8 stuff...";

    DoSomething(s);
}

The above code compiles successfully in C++17 mode.

Now you want to be cool and update your language standard to C++20, because, you know, we are in 2026 😉

Well, surprise, surprise…the same code will not compile in C++20 mode!

MSVC compilation error involving u8 and char8_t when switching to C++20 mode.
Microsoft VC++ compilation error when switching to C++20 mode.

The MSVC compiler complains with the following error message:

‘void DoSomething(const char *)’: cannot convert argument 1 from ‘const char8_t *’ to ‘const char *’

The reason for that is that until C++20 a u8 string literal was interpreted as a const char array; on the other hand, C++20 did introduce a breaking change, and the same u8 string literal is now a const char8_t array in the new standard!

u8″…” SyntaxTypeEncoding
Until C++20
(C++11, 14, 17)
const char[N]UTF-8
Since C++20const char8_t[N]UTF-8

The DoSomething function expects a char-based string, not a char8_t-based string, and so the C++ compiler complains in C++20 mode.

Of course, this was a simple example to illustrate the nature of the problem. But suppose that you are working with large libraries and existing codebases that used to compile just fine in previous C++ standards (e.g. C++17), and now the same code break all of a sudden when you switch to C++20 mode!

To mitigate the problem, an option could be to avoid the use of the u8 prefix when possible.

For example, this is what Google’s C++ Style Guide currently suggests:

When possible, avoid the u8 prefix. It has significantly different semantics starting in C++20 than in C++17, producing arrays of char8_t rather than char, and will change again in C++23.

Leave a comment