Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem using wscanf in c for wide characters

Tags:

c

unicode

I am trying to enter 3 characters, one of which is å. Here is the code:

#ifdef _MSC_VER
#include <io.h>     // _setmode
#include <fcntl.h>  // _O_U16TEXT
#endif

#include <stdio.h>
#include <locale.h>
#include <wchar.h>
#define SIZE 4

void set_locale_mode() {
   #ifdef _MSC_VER
   // Unicode UTF-16, little endian byte order (BMP of ISO 10646)
   const char *CP_UTF_16LE = ".1200";

   setlocale(LC_ALL, CP_UTF_16LE);
   _setmode(_fileno(stdout), _O_U16TEXT);
   #else
      setlocale(LC_ALL, "");
   #endif
}


int main(void) {

   set_locale_mode(); 
   wchar_t myString[SIZE];
   wchar_t testChar=0x00E5;

   wprintf(L"Your test character is %lc\n", testChar);
   printf("Now, enter 3 characters: ");
   wscanf(L"%ls", myString);
   wprintf(L"Your input is %ls\n", myString);

   return 0;
}

However when I enter for example blå I get this output:

You test character is å
Now, enter 3 characters: blå 
Your input is bl┼

Why does not å get printed correctly after I use wscanf?

I am on windows.

like image 425
Alexander Jonsson Avatar asked Oct 24 '25 01:10

Alexander Jonsson


1 Answers

Since you want input to be using _O_U16TEXT too, add that to the set_locale_mode function.

I also suggest not mixing "wide" output with narrow, like wprintf and printf.

#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__)
// perhaps there is already a macro for this, but I don't know of one:
#define ON_WINDOWS
#endif

#ifdef ON_WINDOWS
#define _CRT_SECURE_NO_WARNINGS
#include <io.h>     // _setmode
#include <fcntl.h>  // _O_U16TEXT

// just in case mingw doesn't define it after all:
#ifndef _O_U16TEXT
#define _O_U16TEXT (0x20000)
#endif
#endif

#include <stdio.h>
#include <locale.h>
#include <wchar.h>
#define SIZE 4

void set_locale_mode() {
#ifdef ON_WINDOWS
    // Unicode UTF-16, little endian byte order (BMP of ISO 10646)
    const char* CP_UTF_16LE = ".1200";

    setlocale(LC_ALL, CP_UTF_16LE);
    _setmode(_fileno(stdin), _O_U16TEXT);                // <- Added
    _setmode(_fileno(stdout), _O_U16TEXT);
#else
    setlocale(LC_ALL, "");
#endif
}


int main(void) {
    set_locale_mode();

    wchar_t myString[SIZE];
    wchar_t testChar = u'\u00E5'; // shows intent clearer than 0x00E5

    wprintf(L"Your test character is %lc\n", testChar);
    wprintf(L"Now, enter 3 characters: ");              // <- Use wprintf here
    wscanf(L"%3ls", myString); // <- limit to 3 since SIZE is 4
    wprintf(L"Your input is %ls\n", myString);
}
like image 147
Ted Lyngmo Avatar answered Oct 26 '25 16:10

Ted Lyngmo