Search code examples
cc99wcharwidechar

putwchar() can't diplay a wchar_t variable


Why printf() can display é (\u00E9 int UTF-16) and putwchar() can't ?

And what is the right syntax to get putwchar displaying é correctly ?

#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>
#include <locale.h>

int main() {
  wint_t wc = L'\u00E9';

  setlocale(LC_CTYPE, "fr_FR.utf8");

  printf("%C\n", wc);
  putwchar((wchar_t)wc);
  putchar('\n');

  return 0;
}

Environnement

  • OS : openSUSE Leap 42.1
  • compiler : gcc version 4.8.5 (SUSE Linux)
  • Terminal : Terminator
  • Terminal encoding : UTF-8
  • Shell : zsh
  • CPU : x86_64

Shell env :

env | grep LC && env | grep LANG
LC_CTYPE=fr_FR.utf8
LANG=fr_FR.UTF-8
GDM_LANG=fr_FR.utf8

Edit

in :

wint_t  wc = L'\u00E9'
setlocale(LC_CTYPE, "");

out:

C3 A9 0A E9 0A

in:

wint_t wc = L'\xc3a9';               
setlocale(LC_CTYPE, "");

out:

EC 8E A9 0A A9 0A

Solution

  • You cannot mix wide character and byte input/output functions (printf is a byte output function, regardless if it includes formats for wide characters) on the same stream. The orientation of a stream can only be reset with freopen, which must be done again before calling the byte-oriented putchar function.

    #include <stdlib.h>
    #include <stdio.h>
    #include <wchar.h>
    #include <locale.h>
    
    int main() {
        wint_t wc = L'\u00E9';
    
        setlocale(LC_CTYPE, "");
    
        printf("%lc\n", wc);
        freopen(NULL, "w", stdout);
        putwchar((wchar_t)wc);
        freopen(NULL, "w", stdout);
        putchar('\n');
    
        return 0;
    }
    

    The fact that the orientation can only be set by reopening the stream indicates that this is not intended to be done trivially, and most programs should use only one kind of output. (i.e. either wprintf/putwchar, or printf/putchar, using printf or wctomb if you need to print a wide character)