cwindowswinapicmd

Having trouble setting chcp in C language


I'm a new learner of the C programming language, and I've been having trouble setting up some code I made for a small quiz in Brazilian Portuguese. Here it is:

#include <stdio.h>
#include <windows.h>
#include <locale.h>
#include <unistd.h>

int main() {
    int menu_principal;

    // Configura o terminal para usar UTF-8
    // Permite que o sistema leia letras com acento e outras como cedilha
    
    // SetConsoleOutputCP(CP_UTF8); // Não é necessário

    while(1) {
        

        // Lembrete: system("cls") limpa a tela
        system("cls");
        system("chcp 1252");

        // Menu principal
        printf("Digite o número correspondente a sua escolha:\n");
        printf("1. Iniciar o quiz\n");
        printf("2. Mostrar o resultado\n");
        printf("3. Limpar respostas\n");
        printf("4. Sair\n");
        printf("\n");
        printf("Escolha uma das opções: ");
        scanf("%d", &menu_principal);

        // Switch case para o menu principal
        switch(menu_principal) {
            case 1:
                // function
                break;
            case 2:
                // function
                break;
            case 3:
                // function
                break;
            case 4:
                // function
            default:
                // function
        }
    }
}

I've been trying for a while now to make the code page change to 1252/65001 and it simply doesn't work, is it just me?


EDIT:

Here's the image as asked:

image

On CMD, it also didn't work on PowerShell. The same code I used to accept special characters worked on a friend's computer.


EDIT:

Editor's note: Something's fishy. This code works on some computers but not others.


Solution

  • at first about call to

    system("chcp N");
    

    this create new process, based on chcp.com, which call SetConsoleOutputCP(N) (and of course do many other api calls). so if need set output code page, direct call SetConsoleOutputCP and never system("chcp N");

    now about main problem. you use printf. so your input text in multibyte. windows UI use unicode (wide char). so your text must be converted to unicode first. this is done by using MultiByteToWideChar api. what is CodePage (1-st parameter of MultiByteToWideChar) must be used ? it must match the encoding of your source file ("quiz.c"). this is the encoding in which the line is in your source file, in this same encoding it will get into the binary exe and will be transferred to printf i dot know in which encoding is quiz.c is saved on your system, but you must use this and only this encoding in code. also this your file encoding can initially loss some info, so can not be correct converted to unicode anyway. but probably in this case you will get C4566 warning:

    character represented by universal-character-name 'char' cannot be represented in the current code page (page). Not every Unicode character can be represented in your current ANSI code page.

    The same code I used to accept special characters worked on a friend's computer.

    are binary version, build on your comp (where encoding already embeded), work ? i doubt (this must not be). or the exe builded from source code on another comp and another encoding use for source file/strings ? i guess this.

    in any case you can not set any encoding in call SetConsoleOutputCP(N) but only encoding of your src file. you can use SetConsoleOutputCP(CP_UTF8); only in case your src file (strings passed to printf ) is in utf8 encoding.

    and always better use src lines in wide char (unicode) from begin. use WriteConsoleW but not use wprintf - this is worst possible choise. because wprintf first convert input unicode to multibyte by wctomb_s. so you by fact got 2 conversions - first from unicode to multibyte, by locale in your current process and then from multibyte to unicode by codepage in conhost.exe (not your exe) which you set by SetConsoleOutputCP


    effect of setlocale call on printf :

    enter image description here

    the right image is what is happens inside _write_nolock ( called inside printf) in case setlocale is not called before. and the left image - how is _write_nolock after call to setlocale

    the different is huge.

    in case setlocale is not called - simply WriteFile( s, strlen(s) ) is called (where s is string passed to printf(s) and conhost.exe do next:

    enter image description here

    call MultiByteToWideChar with CodePage equal to SetConsoleOutputCP()

    so here we have single WriteFile call which handled inside conhost.exe and single MultiByteToWideChar call where codepage is set by SetConsoleOutputCP()

    but what is happens after setlocale ? no processing became absolute different. in current process, every characters in string first convert to corresponding wide character via mbtowc. which internal call MultiByteToWideChar with CodePage based to setlocale argument. then wide character converted back to multibyte character with WideCharToMultiByte and CodePage = GetConsoleCP() ( Retrieves the input code page used by the console associated with the calling process ). yes, not GetConsoleOutputCP() ( Retrieves the output code page used by the console associated with the calling process ). then call WriteFile for single character . and in conhost again will be call MultiByteToWideChar ( GetConsoleOutputCP())

    so here we have 3 tranforms in loop:

    while (char*c = *str++)
    {
      wchar_t w;
      MultiByteToWideChar (fn(locale from setlocale), 0, &c, 1, &w, 1);
      WideCharToMultiByte(GetConsoleCP(), 0, &w, 1, &c, 1, 0, 0);
      WriteFile(, &c, 1, );
      //++conhost
      MultiByteToWideChar (GetConsoleOutputCP(), 0, &c, 1,  )
      //--conhost
    }
    

    and if we have N chars in string will be N calls to WriteFile - so to kernel and then to remote process conhost.exe

    when in case no setlocale will be next:

      WriteFile(, str, strlen(str), );
      //++conhost
      MultiByteToWideChar (GetConsoleOutputCP(), 0, str, strlen(str),  )
      //--conhost
    

    (no loops, sigle call to WriteFile and MultiByteToWideChar)