Android < 5.0 had only dummy locales. Starting with Android 5.0 (according to the Android libc's git history), they have locales. But there are two problems: 1) The default locale (i.e. the locale in use when setlocale was not called) is the "C.UTF-8" locale, not the "C" locale. Test case: ================================================================================ #include #include #include int main () { printf ("Locale=|%s| LC_CTYPE=|%s| MB_CUR_MAX=%d\n", setlocale (LC_ALL, NULL), setlocale (LC_CTYPE, NULL), (int) MB_CUR_MAX); } ================================================================================ prints Locale=|C.UTF-8| LC_CTYPE=|C.UTF-8| MB_CUR_MAX=4 rather than the expected Locale=|C| LC_CTYPE=|C| MB_CUR_MAX=1 POSIX says that the default locale should be the "C"/"POSIX" locale. 2) A setlocale call that is meant to set the "C" or "POSIX" locale actually sets a locale with UTF-8 encoding. Test case 1: ================================================================================ #include #include #include #include #include int main () { mbstate_t state; if (setlocale (LC_ALL, "") == NULL) return 1; memset (&state, '\0', sizeof (state)); printf ("Locale=|%s| LC_CTYPE=|%s| MB_CUR_MAX=%d mbrtowc(0xC0)=%d\n", setlocale (LC_ALL, NULL), setlocale (LC_CTYPE, NULL), (int) MB_CUR_MAX, (int) mbrtowc (NULL, "\xC0", 1, &state)); } ================================================================================ $ LC_ALL=C ./a.out and $ LC_ALL=POSIX ./a.out print Locale=|C.UTF-8| LC_CTYPE=|C.UTF-8| MB_CUR_MAX=4 mbrtowc(0xC0)=-2 rather than the expected Locale=|C| LC_CTYPE=|C| MB_CUR_MAX=1 mbrtowc(0xC0)=-1 Test case 2: ================================================================================ #include #include #include #include #include int main () { mbstate_t state; if (setlocale (LC_ALL, "C") == NULL) return 1; memset (&state, '\0', sizeof (state)); printf ("Locale=|%s| LC_CTYPE=|%s| MB_CUR_MAX=%d mbrtowc(0xC0)=%d\n", setlocale (LC_ALL, NULL), setlocale (LC_CTYPE, NULL), (int) MB_CUR_MAX, (int) mbrtowc (NULL, "\xC0", 1, &state)); if (setlocale (LC_ALL, "POSIX") == NULL) return 1; memset (&state, '\0', sizeof (state)); printf ("Locale=|%s| LC_CTYPE=|%s| MB_CUR_MAX=%d mbrtowc(0xC0)=%d\n", setlocale (LC_ALL, NULL), setlocale (LC_CTYPE, NULL), (int) MB_CUR_MAX, (int) mbrtowc (NULL, "\xC0", 1, &state)); } ================================================================================ prints Locale=|C| LC_CTYPE=|C| MB_CUR_MAX=4 mbrtowc(0xC0)=-2 Locale=|C| LC_CTYPE=|C| MB_CUR_MAX=4 mbrtowc(0xC0)=-2 rather than the expected Locale=|C| LC_CTYPE=|C| MB_CUR_MAX=1 mbrtowc(0xC0)=-1 Locale=|C| LC_CTYPE=|C| MB_CUR_MAX=1 mbrtowc(0xC0)=-1 One of the consequences are these two test failures: FAIL: test-mbrtoc32-5.sh ======================== ../../gltests/test-mbrtoc32.c:105: assertion 'ret == 1' failed Aborted FAIL test-mbrtoc32-5.sh (exit status: 134) FAIL: test-mbrtowc5.sh ====================== ../../gltests/test-mbrtowc.c:105: assertion 'ret == 1' failed Aborted FAIL test-mbrtowc5.sh (exit status: 134) As a workaround, I'm applying these two patches. 2023-01-16 Bruno Haible mbrtowc, mbrtoc32 tests: Avoid test failure on Android ≥ 5.0. * tests/test-mbrtowc.c (main): On Android 5.0 or newer, when testing the "C" locale, verify that the encoding is UTF-8. * tests/test-mbrtoc32.c (main): Likewise. * doc/posix-functions/setlocale.texi: Mention the Android problems. mbrtowc, mbrtoc32 tests: Refactor. * tests/test-mbrtowc.c (main): Straighten convoluted code. * tests/test-mbrtoc32.c (main): Likewise.