CodeNebula
C++20coreadvanced

char8_t (C++20 Addition)

C++20 · The Big Four · Compiler flag: -std=c++20

Explanation

A new fundamental type specifically for UTF-8 encoded characters, distinct from `char` and `unsigned char`. This provides type safety for UTF-8 strings and prevents accidental mixing of character encodings. The type `u8string` and `u8string_view` use `char8_t` as their character type.

Real-World Scenario

Enforce correct UTF-8 handling in an internationalized application where mixing encodings would cause display corruption.

Quick Snippet

snippet.cpp
#include <string>

char8_t c = u8'A';
std::u8string greeting = u8"Hello, World!";
// const char* p = u8"test";  // Error in C++20: u8 literals are char8_t[], not char[]

// Use char8_t to ensure UTF-8 encoding at the type level
std::u8string load_utf8_file(const std::filesystem::path& path);

Full Example

char8_t.cpp
// CodeNebula - C++20 Example: char8_t
// Compile: g++ -std=c++20 -Wall -Wextra -o example char8_t.cpp

// Demonstrates the C++20 char8_t type for UTF-8 encoded character data,
// u8 string literals, and conversion between char8_t and char.

#include <iostream>
#include <string>
#include <cstring>
#include <type_traits>

// ------------------------------------------------------------------
// Helper: convert u8string to regular string for printing
// ------------------------------------------------------------------
std::string to_string(const std::u8string& u8s) {
    return std::string(reinterpret_cast<const char*>(u8s.data()), u8s.size());
}

std::string to_string(const char8_t* u8s) {
    return std::string(reinterpret_cast<const char*>(u8s));
}

int main()
{
    // ------------------------------------------------------------------
    // 1. char8_t is a distinct type in C++20
    // ------------------------------------------------------------------
    std::cout << "=== char8_t Type Properties ===" << std::endl;
    std::cout << "  sizeof(char8_t):  " << sizeof(char8_t) << std::endl;
    std::cout << "  sizeof(char):     " << sizeof(char) << std::endl;
    std::cout << "  same as char?     "
              << std::is_same_v<char8_t, char> << std::endl;
    std::cout << "  same as unsigned char? "
              << std::is_same_v<char8_t, unsigned char> << std::endl;
    std::cout << "  is unsigned?      " << std::is_unsigned_v<char8_t> << std::endl;

    // ------------------------------------------------------------------
    // 2. u8 character and string literals produce char8_t
    // ------------------------------------------------------------------
    std::cout << "\n=== u8 Literals ===" << std::endl;
    char8_t ch = u8'A';
    std::cout << "  u8'A' value: " << static_cast<int>(ch) << std::endl;

    const char8_t* u8lit = u8"Hello, UTF-8!";
    std::cout << "  u8 literal: " << to_string(u8lit) << std::endl;

    // ------------------------------------------------------------------
    // 3. std::u8string
    // ------------------------------------------------------------------
    std::cout << "\n=== std::u8string ===" << std::endl;
    std::u8string u8s = u8"C++20 char8_t";
    std::cout << "  Content: " << to_string(u8s) << std::endl;
    std::cout << "  Size:    " << u8s.size() << " code units" << std::endl;
    std::cout << "  Empty?   " << u8s.empty() << std::endl;

    // ------------------------------------------------------------------
    // 4. Multi-byte UTF-8 sequences
    // ------------------------------------------------------------------
    std::cout << "\n=== Multi-byte UTF-8 ===" << std::endl;
    std::u8string emoji = u8"\xC2\xA9";  // copyright sign (2 bytes)
    std::cout << "  Copyright sign bytes: " << emoji.size() << std::endl;

    std::u8string euro = u8"\xE2\x82\xAC";  // euro sign (3 bytes)
    std::cout << "  Euro sign bytes: " << euro.size() << std::endl;

    // ------------------------------------------------------------------
    // 5. Concatenation and operations
    // ------------------------------------------------------------------
    std::cout << "\n=== u8string Operations ===" << std::endl;
    std::u8string greeting = u8"Hello";
    std::u8string world = u8" World";
    std::u8string combined = greeting + world;
    std::cout << "  Concat: " << to_string(combined) << std::endl;
    std::cout << "  Length: " << combined.size() << std::endl;

    auto pos = combined.find(u8"World");
    std::cout << "  'World' found at position: " << pos << std::endl;

    std::u8string sub = combined.substr(6, 5);
    std::cout << "  Substr(6,5): " << to_string(sub) << std::endl;

    // ------------------------------------------------------------------
    // 6. Iterating over code units
    // ------------------------------------------------------------------
    std::cout << "\n=== Iterating Code Units ===" << std::endl;
    std::u8string abc = u8"ABC";
    std::cout << "  Code units of 'ABC':";
    for (char8_t c : abc) {
        std::cout << " " << static_cast<int>(c);
    }
    std::cout << std::endl;

    return 0;
}

/*
Expected output:

=== char8_t Type Properties ===
  sizeof(char8_t):  1
  sizeof(char):     1
  same as char?     0
  same as unsigned char? 0
  is unsigned?      1

=== u8 Literals ===
  u8'A' value: 65
  u8 literal: Hello, UTF-8!

=== std::u8string ===
  Content: C++20 char8_t
  Size:    13 code units
  Empty?   0

=== Multi-byte UTF-8 ===
  Copyright sign bytes: 2
  Euro sign bytes: 3

=== u8string Operations ===
  Concat: Hello World
  Length: 11
  'World' found at position: 6
  Substr(6,5): World

=== Iterating Code Units ===
  Code units of 'ABC': 65 66 67
*/
Run command
g++ -std=c++20 -Wall -Wextra -o example char8_t.cpp