liveBook · Manning

Extended character set

As explained in Modern C

An extended character set is a character repertoire that includes characters beyond the C basic character set.

Printing characters beyond the basic set

#include <locale.h> #include <stdio.h> int main(void) { setlocale(LC_ALL, ""); fputs("fär ínóff\n", stdout); return 0; } The call to setlocale matters: without a suitable locale, extended characters may appear as garbage on the terminal. Even with the call, useful output depends on the system being suitably installed. section 14.3

An extended character set includes characters beyond C’s basic character set. A multibyte character represents one such character as a sequence of bytes; a multibyte string contains these sequences. TAKEAWAY: Multibyte characters contain no null bytes, and multibyte strings are null terminated. Ordinary string functions such as strcpy can therefore handle them, but byte counts are not character counts. section 14.3

  void draw_sep(char const start[static 1],
                char const end[static 1]) {
    fputs(start, stdout);
    size_t slen = mbsrlen(start, 0);
    size_t elen = 90 - mbsrlen(end, 0);
    for (size_t i = slen; i < elen; ++i) fputs(HBAR, stdout);
    fputs(end, stdout);
    fputc('\n', stdout);
  }
!@%STYLE%@!
{"css":"{\"css\": \"font-weight: bold;\"}","target":"[[{\"line\":0,\"ch\":0},{\"line\":0,\"ch\":4}],[{\"line\":0,\"ch\":14},{\"line\":0,\"ch\":24}],[{\"line\":1,\"ch\":16},{\"line\":1,\"ch\":26}],[{\"line\":0,\"ch\":31},{\"line\":0,\"ch\":37}],[{\"line\":1,\"ch\":31},{\"line\":1,\"ch\":37}],[{\"line\":0,\"ch\":14},{\"line\":0,\"ch\":24}],[{\"line\":1,\"ch\":16},{\"line\":1,\"ch\":26}],[{\"line\":0,\"ch\":31},{\"line\":0,\"ch\":37}],[{\"line\":1,\"ch\":31},{\"line\":1,\"ch\":37}],[{\"line\":2,\"ch\":4},{\"line\":2,\"ch\":9}],[{\"line\":5,\"ch\":41},{\"line\":5,\"ch\":46}],[{\"line\":6,\"ch\":4},{\"line\":6,\"ch\":9}],[{\"line\":2,\"ch\":17},{\"line\":2,\"ch\":23}],[{\"line\":5,\"ch\":53},{\"line\":5,\"ch\":59}],[{\"line\":6,\"ch\":15},{\"line\":6,\"ch\":21}],[{\"line\":7,\"ch\":16},{\"line\":7,\"ch\":22}],[{\"line\":3,\"ch\":4},{\"line\":3,\"ch\":10}],[{\"line\":4,\"ch\":4},{\"line\":4,\"ch\":10}],[{\"line\":5,\"ch\":9},{\"line\":5,\"ch\":15}],[{\"line\":3,\"ch\":4},{\"line\":3,\"ch\":10}],[{\"line\":4,\"ch\":4},{\"line\":4,\"ch\":10}],[{\"line\":5,\"ch\":9},{\"line\":5,\"ch\":15}],[{\"line\":5,\"ch\":4},{\"line\":5,\"ch\":7}],[{\"line\":3,\"ch\":4},{\"line\":3,\"ch\":10}],[{\"line\":4,\"ch\":4},{\"line\":4,\"ch\":10}],[{\"line\":5,\"ch\":9},{\"line\":5,\"ch\":15}],[{\"line\":2,\"ch\":4},{\"line\":2,\"ch\":9}],[{\"line\":5,\"ch\":41},{\"line\":5,\"ch\":46}],[{\"line\":6,\"ch\":4},{\"line\":6,\"ch\":9}],[{\"line\":2,\"ch\":17},{\"line\":2,\"ch\":23}],[{\"line\":5,\"ch\":53},{\"line\":5,\"ch\":59}],[{\"line\":6,\"ch\":15},{\"line\":6,\"ch\":21}],[{\"line\":7,\"ch\":16},{\"line\":7,\"ch\":22}],[{\"line\":2,\"ch\":4},{\"line\":2,\"ch\":9}],[{\"line\":5,\"ch\":41},{\"line\":5,\"ch\":46}],[{\"line\":6,\"ch\":4},{\"line\":6,\"ch\":9}],[{\"line\":2,\"ch\":17},{\"line\":2,\"ch\":23}],[{\"line\":5,\"ch\":53},{\"line\":5,\"ch\":59}],[{\"line\":6,\"ch\":15},{\"line\":6,\"ch\":21}],[{\"line\":7,\"ch\":16},{\"line\":7,\"ch\":22}],[{\"line\":7,\"ch\":4},{\"line\":7,\"ch\":9}],[{\"line\":2,\"ch\":17},{\"line\":2,\"ch\":23}],[{\"line\":5,\"ch\":53},{\"line\":5,\"ch\":59}],[{\"line\":6,\"ch\":15},{\"line\":6,\"ch\":21}],[{\"line\":7,\"ch\":16},{\"line\":7,\"ch\":22}]]"}
!@%STYLE%@!

The draw_sep function prints a line with fputs and fills the space between its ends with horizontal-bar characters. It uses mbsrlen rather than strlen to calculate how many characters the strings represent. section 14.3

The helper mbsrlen is nonstandard. It measures a multibyte string as a wide-character string and reports an encoding error with a return value of -1. Its conversion state must match the character at which counting begins; the helper does not modify that state. section 14.3

30   size_t mbsrlen(char const*s, mbstate_t const*restrict state) {
31     if (!state) state = MBSTATE;
32     mbstate_t st = *state;
33     size_t mblen = mbsrtowcs(0, &s, 0, &st);
34     if (mblen == -1) errno = 0;
35     return mblen;
36   }


!@%STYLE%@!
{"css":"{\"css\": \"font-weight: bold;\"}","target":"[[{\"line\":0,\"ch\":0},{\"line\":0,\"ch\":2}],[{\"line\":0,\"ch\":5},{\"line\":0,\"ch\":11}],[{\"line\":3,\"ch\":7},{\"line\":3,\"ch\":13}],[{\"line\":0,\"ch\":20},{\"line\":0,\"ch\":30}],[{\"line\":0,\"ch\":34},{\"line\":0,\"ch\":43}],[{\"line\":2,\"ch\":7},{\"line\":2,\"ch\":16}],[{\"line\":0,\"ch\":25},{\"line\":0,\"ch\":30}],[{\"line\":0,\"ch\":50},{\"line\":0,\"ch\":58}],[{\"line\":1,\"ch\":0},{\"line\":1,\"ch\":2}],[{\"line\":1,\"ch\":7},{\"line\":1,\"ch\":9}],[{\"line\":4,\"ch\":7},{\"line\":4,\"ch\":9}],[{\"line\":2,\"ch\":0},{\"line\":2,\"ch\":2}],[{\"line\":0,\"ch\":34},{\"line\":0,\"ch\":43}],[{\"line\":2,\"ch\":7},{\"line\":2,\"ch\":16}],[{\"line\":3,\"ch\":0},{\"line\":3,\"ch\":2}],[{\"line\":0,\"ch\":5},{\"line\":0,\"ch\":11}],[{\"line\":3,\"ch\":7},{\"line\":3,\"ch\":13}],[{\"line\":3,\"ch\":14},{\"line\":3,\"ch\":19}],[{\"line\":4,\"ch\":11},{\"line\":4,\"ch\":16}],[{\"line\":5,\"ch\":14},{\"line\":5,\"ch\":19}],[{\"line\":3,\"ch\":22},{\"line\":3,\"ch\":31}],[{\"line\":4,\"ch\":0},{\"line\":4,\"ch\":2}],[{\"line\":1,\"ch\":7},{\"line\":1,\"ch\":9}],[{\"line\":4,\"ch\":7},{\"line\":4,\"ch\":9}],[{\"line\":3,\"ch\":14},{\"line\":3,\"ch\":19}],[{\"line\":4,\"ch\":11},{\"line\":4,\"ch\":16}],[{\"line\":5,\"ch\":14},{\"line\":5,\"ch\":19}],[{\"line\":4,\"ch\":24},{\"line\":4,\"ch\":29}],[{\"line\":5,\"ch\":0},{\"line\":5,\"ch\":2}],[{\"line\":5,\"ch\":7},{\"line\":5,\"ch\":13}],[{\"line\":3,\"ch\":14},{\"line\":3,\"ch\":19}],[{\"line\":4,\"ch\":11},{\"line\":4,\"ch\":16}],[{\"line\":5,\"ch\":14},{\"line\":5,\"ch\":19}],[{\"line\":6,\"ch\":0},{\"line\":6,\"ch\":2}]]"}
!@%STYLE%@!

The mbsrlen implementation copies its conversion state, then calls mbsrtowcs with no destination to obtain the length. The separate mbsrdup example uses that length to allocate and convert a wide-character copy. section 14.3

TAKEAWAY: Use multibyte strings for extended-character input and output, but check conversions and do not infer their character length from strlen or a char array’s size. section 14.3 section 14.6

How Modern C covers it

How deep it goes
Defines multibyte characters and strings, then works through locale setup, character counting, conversion state, and helper implementations.
Examples
Uses extended-character terminal output, a drawn separator, and helpers for measuring and converting multibyte strings.
What it assumes
Assumes familiarity with pointers and ordinary C strings, while defining multibyte characters and strings in context.
What you can do after
Apply it via C’s setlocale and multibyte conversion functions to print and count extended characters while checking encoding errors.
How it connects
Connects extended character sets to locales, null-terminated strings, wide characters, and multibyte conversion.

Also explained in

Compare how 2 books explain extended character set →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Modern C. The section links point to the parts of the book it draws on.