Back to C++
2026-01-208 min read

UTF-8 as a portable source file encoding (C++)

Learn UTF-8 as a portable source file encoding (C++) step by step with clear examples and exercises.

Why This Matters

In today's globalized world, it is crucial to write code that can handle various character sets, including non-English languages. UTF-8 is a versatile encoding standard that supports virtually every written language in the world. Using UTF-8 as your source file encoding in C++ ensures your programs can read and write files containing characters from different languages without issues. This is crucial for creating applications that cater to diverse user bases, making it an essential skill for modern software development.

In this lesson, we will explore the ins and outs of UTF-8 in C++, including its benefits, prerequisites, core concepts, worked examples, common mistakes, practice questions, and frequently asked questions.

Prerequisites

To fully grasp this lesson, you should have a basic understanding of:

  1. C++ programming language fundamentals
  2. File handling in C++
  3. Basic concepts related to character encodings and Unicode
  4. Familiarity with the standard template library (STL), including containers like std::string and input/output streams like std::ifstream and std::ofstream.
  5. Understanding of wide characters (wchar_t) and their usage in C++

If you're new to these topics, consider checking out our resources on C++ basics, file handling, character encodings, Unicode, and STL before diving into this lesson.

Core Concept

Understanding UTF-8

UTF-8 is a variable-length encoding that represents each character as one to four bytes. It's backward compatible with ASCII, meaning it can handle all 127 ASCII characters using a single byte. For other Unicode characters, UTF-8 uses multiple bytes. This flexibility makes UTF-8 an ideal choice for modern software development.

In UTF-8, each character is represented as a sequence of one or more bytes, with the most significant bit (MSB) of the first byte indicating the number of additional bytes needed to represent the character. For example:

  • ASCII characters (7 bits): 0xxxxxxx
  • Two-byte UTF-8 characters (11 bits): 110xxxxx 10xxxxxx
  • Three-byte UTF-8 characters (16 bits): 1110xxxx 10xxxxxx 10xxxxxx
  • Four-byte UTF-8 characters (21 bits): 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

C++ and UTF-8

In C++, you can work with UTF-8 encoded files by using the standard input/output streams (std::ifstream, std::ofstream) or file manipulation functions like fopen(), fread(), and fwrite(). When reading a UTF-8 encoded file, C++ automatically handles the variable-length encoding, allowing you to read characters of any length.

When writing to a file, it's important to ensure that each character is written as a valid UTF-8 sequence. The standard library provides functions like std::putchar() and std::putwchar() for writing individual characters, but they do not guarantee UTF-8 compatibility. Instead, use the string stream manipulator std::ws to write wide characters (wchar_t) as UTF-8 encoded sequences:

std::ofstream outputFile("output.txt", std::ios::out);
outputFile << std::use_facet<std::codecvt_utf8<wchar_t> >(locale()).put(wchar_t('Hello'), std::codecvt_mode(0));

Reading and Writing UTF-8 Files in C++

Reading a UTF-8 encoded file using input/output streams is straightforward:

std::ifstream inputFile("example.txt", std::ios::in);
if (inputFile.is_open()) {
std::string line;
while (getline(inputFile, line)) {
std::cout << line << std::endl;
}
inputFile.close();
} else {
std::cerr << "Unable to open file example.txt" << std::endl;
}

Writing to a UTF-8 encoded file using the string stream manipulator std::ws is also simple:

std::ofstream outputFile("output.txt", std::ios::out);
if (outputFile.is_open()) {
outputFile << "Hello, World!\n";
outputFile << std::use_facet<std::codecvt_utf8<wchar_t> >(locale()).put(wchar_t('こんにちは、世界!'), std::codecvt_mode(0));
outputFile.close();
} else {
std::cerr << "Unable to open file output.txt" << std::endl;
}

Compiler Support

Most modern C++ compilers support UTF-8 as the default source file encoding. If your compiler doesn't, you can specify it using command-line options or configuration files.

Worked Example

Let's create a simple C++ program that reads and writes UTF-8 encoded files using both input/output streams and file manipulation functions.

#include <iostream>
#include <fstream>
#include <string>
#include <codecvt>

int main() {
// Read from a UTF-8 encoded file using input/output streams
std::ifstream inputFile("example.txt", std::ios::in);
if (inputFile.is_open()) {
std::string line;
while (getline(inputFile, line)) {
std::cout << line << std::endl;
}
inputFile.close();
} else {
std::cerr << "Unable to open file example.txt" << std::endl;
}

// Read from a UTF-8 encoded file using file manipulation functions
std::ifstream u8file("example.txt", std::ios::binary);
if (u8file.is_open()) {
std::wstring wideLine;
std::transform(std::istreambuf_iterator<char>(u8file), {}, std::back_inserter<std::wstring>(wideLine), [](unsigned char c) { return static_cast<wchar_t>(c); });
std::wcout << wideLine << std::endl;
u8file.close();
} else {
std::cerr << "Unable to open file example.txt" << std::endl;
}

// Write to a UTF-8 encoded file using input/output streams
std::ofstream outputFile("output.txt", std::ios::out);
if (outputFile.is_open()) {
outputFile << "Hello, World!\n";
outputFile << std::use_facet<std::codecvt_utf8<wchar_t> >(locale()).put(wchar_t('こんにちは、世界!'), std::codecvt_mode(0));
outputFile.close();
} else {
std::cerr << "Unable to open file output.txt" << std::endl;
}

// Write to a UTF-8 encoded file using file manipulation functions
std::ofstream u8output("output.txt", std::ios::binary | std::ios::app);
if (u8output.is_open()) {
std::transform(std::begin(L"Hello, World!\n"), std::end(L"Hello, World!\n"), std::ostreambuf_iterator<char>(u8output), [](wchar_t c) { return static_cast<unsigned char>(c); });
u8output << std::putwchar(0); // Add null terminator for safety (optional)
std::transform(std::begin(L"こんにちは、世界!"), std::end(L"こんにちは、世界!"), std::ostreambuf_iterator<char>(u8output), [](wchar_t c) { return static_cast<unsigned char>(c); });
u8output.close();
} else {
std::cerr << "Unable to open file output.txt" << std::endl;
}

return 0;
}

In this example, we read a UTF-8 encoded file named example.txt using both input/output streams and file manipulation functions. We then write to another file called output.txt, demonstrating that our program can handle multiple languages using UTF-8 encoding.

Common Mistakes

  1. Forgetting to include the correct headers: Ensure you have included the necessary headers for file handling (`), wide character support (), and string manipulation (`).
  2. Not checking if files are open before reading or writing: Always check whether a file is successfully opened before attempting to read from it or write to it.
  3. Ignoring errors during file operations: Be sure to handle errors that may occur during file operations, such as file not found or permission denied errors.
  4. Assuming ASCII compatibility: Remember that C++ only guarantees compatibility with the first 127 ASCII characters. Characters outside this range might require additional handling.
  5. Not specifying UTF-8 encoding explicitly: If your compiler doesn't support UTF-8 as the default source file encoding, make sure to specify it using command-line options or configuration files.
  6. Using incorrect functions for writing UTF-8 encoded characters: When writing individual characters, use std::putwchar() and the string stream manipulator std::ws to ensure UTF-8 compatibility.
  7. Not handling wide characters correctly: When reading or writing wide characters (wchar_t), use functions like std::transform to convert between wide characters and char.
  8. Not properly handling multibyte characters: Be aware that some multibyte characters might not be represented correctly in UTF-8, especially if they are outside the BMP (Basic Multilingual Plane).
  9. Not escaping special characters: When working with files containing special characters like \n, make sure to properly escape them to avoid issues during file operations.
  10. Not testing for different character sets: Ensure that your program works correctly with various character sets, including those outside the ASCII range.

Practice Questions

  1. Write a program that reads a UTF-8 encoded file and counts the number of lines in the file using input/output streams.
  2. Modify the example program to read multiple files and print their contents one after another, both using input/output streams and file manipulation functions.
  3. Implement error handling for cases where the input or output files cannot be opened.
  4. Write a function that converts a string from UTF-8 encoding to ASCII (7-bit).
  5. Write a function that checks if a given character is valid in UTF-8 encoding.
  6. Write a program that reads a UTF-8 encoded file and counts the number of characters in each line, both using input/output streams and file manipulation functions.
  7. Write a program that converts an ASCII (7-bit) encoded file to UTF-8 encoding.
  8. Write a program that validates a given string for UTF-8 compatibility.
  9. Write a function that escapes special characters in a UTF-8 encoded string, ensuring proper handling during file operations.
  10. Write a program that reads a UTF-8 encoded file and translates all occurrences of a specific word within the file using a provided dictionary.

FAQ

Q: Can I use other character encodings in C++ besides UTF-8?

A: Yes, you can use other character encodings like UTF-16 and UTF-32 in C++. However, UTF-8 is the most widely used encoding due to its compatibility with ASCII and efficiency in handling various languages.

Q: How do I specify UTF-8 as the source file encoding for my compiler?

A: The method for specifying UTF-8 as the source file encoding depends on your compiler. For example, in GCC, you can use the -finput-charset=utf8 option. Consult your compiler's documentation for specific instructions.

Q: What happens if I try to read a non-UTF-8 encoded file using C++?

A: If you attempt to read a non-UTF-8 encoded file using C++, the program might not work correctly, especially when dealing with characters outside the ASCII range. It's essential to ensure that your files are encoded in UTF-8 or convert them if necessary.

Q: How can I check if a given string is valid UTF-8?

A: To check if a given string is valid UTF-8, you can use the std::codecvt_utf8 facet to parse the string and catch any exceptions that might be thrown during parsing. If no exceptions are thrown, the string is considered valid UTF-8.

Q: How can I convert a string from ASCII (7-bit) encoding to UTF-8 in C++?

UTF-8 as a portable source file encoding (C++) | C++ | XQA Learn