簡體   English   中英

為什么 ANSI 在第一次調用 function 時打印代碼並在第二次打印顏色?

[英]Why is ANSI printing the code the first time the function is called and printing colours the second time around?

我正在嘗試在 connect 4 游戲中更改我的 printf 語句的顏色 output。 我做了一個 function 來設置打印顏色並重置它。 它適用於我的大部分代碼,但不適用於第一次調用它時調用的第一個 function,但從那里開始工作。 問題中的function是主程序中調用的第一個function。

我嘗試了 function 的不同定位,將它定位在調用 function 的位置的任一側,並將顏色代碼直接輸入到 printf function,但它總是第一次失敗(而且只有第一次)。

#include <stdio.h>
void sprint_green();
void sprint_red();
int main_menu ( void ){
    int a = 0;
    char opt [20];
    sprint_red();
    printf("============================\n");
    printf("    Welcome to Connect4!\n");
    printf("============================\n");
    sprint_reset();
    // Continue asking for an option until a valid option (n/l/q) is entered
    while (a == 0)
    {
        sprint_green();
        printf("(N)ew game\n(L)oad game\n(Q)uit");
        sprint_reset();
        fgets(opt, 20, stdin);
    // if 'n', return 1
        if(opt[0] == 'n' || opt[0] == 'N'){
            a = 1;
        }
    // if 'l', return 2
        else if(opt[0] == 'l' || opt[0] == 'L'){
            a = 2;
        }
    // if 'q', return -1
        else if(opt[0] == 'q' || opt[0] == 'Q'){
            a = -1;
            printf("\nGoodbye!\n");
        }
    // if anything else, give error message and ask again..
        else
        {
            printf("Invalid option\n");
        }
    }
    system("cls");
    return(a);
}

int main (void)
{
    int i;

    for(i = 0; i < 5; i++)
    {
        main_menu();
    }
}

void sprint_green()
{
  printf("\033[1;32m");
}

void sprint_red()
{
  printf("\033[1;31m");
}

void sprint_reset()
{
  printf("\033[0m");
}

前三個 printf 語句預計將打印為紅色,下一個將打印為綠色。 然而,它第一次被稱為打印 ANSI 顏色代碼。

[1;31m============================
    Welcome to Connect4!
============================
[0m[1;32m(N)ew game
(L)oad game
(Q)uit[0m

然而,在運行一次游戲並再次開始(沒有關閉終端)之后,這些功能會按預期工作。

windows命令shell默認不啟動vt100仿真。 正如@Bodo 在他的回答中指出的那樣,這可以通過運行 shell 命令cls來觸發。 但是,從技術上講,shell 命令不需要是cls ,甚至根本不需要是有效命令。 您可以通過一個空的system(" ")調用來觸發它。 這也是可移植的,因為它除了立即啟動 shell 實例並將其終止外什么都不做。 因此它在 Windows 或 Linux 環境中應該同樣可以正常工作。

修復代碼:

#include <stdio.h>
#include <stdlib.h> // for system()

void sprint_green();
void sprint_red();
int main_menu ( void ){
    int a = 0;
    char opt [20];
    system(" "); // Trigger ANSI emulation
    sprint_red();
    printf("============================\n");
    printf("    Welcome to Connect4!\n");
    printf("============================\n");
    sprint_reset();
    // Continue asking for an option until a valid option (n/l/q) is entered
    while (a == 0)
    {
        sprint_green();
        printf("(N)ew game\n(L)oad game\n(Q)uit");
        sprint_reset();
        fgets(opt, 20, stdin);
    // if 'n', return 1
        if(opt[0] == 'n' || opt[0] == 'N'){
            a = 1;
        }
    // if 'l', return 2
        else if(opt[0] == 'l' || opt[0] == 'L'){
            a = 2;
        }
    // if 'q', return -1
        else if(opt[0] == 'q' || opt[0] == 'Q'){
            a = -1;
            printf("\nGoodbye!\n");
        }
    // if anything else, give error message and ask again..
        else
        {
            printf("Invalid option\n");
        }
    }
    system("cls");
    return(a);
}

int main (void)
{
    int i;

    for(i = 0; i < 5; i++)
    {
        main_menu();
    }
}

void sprint_green()
{
  printf("\033[1;32m");
}

void sprint_red()
{
  printf("\033[1;31m");
}

void sprint_reset()
{
  printf("\033[0m");
}

system("cls"); 有效,但它會清除屏幕。 但是如果你只在啟動時調用它一次,它似乎會為整個應用程序修復它

根據
https://solarianprogrammer.com/2019/04/08/c-programming-ansi-escape-codes-windows-macos-linux-terminals/

https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences?redirectedfrom=MSDN
必須將 Windows 控制台置於 ANSI 轉義模式才能處理轉義序列而不是打印它們。

顯然執行cls命令似乎可以做到這一點。

您可以通過設置標志ENABLE_VIRTUAL_TERMINAL_PROCESSING使用GetConsoleMode()SetConsoleMode()以編程方式設置終端模式

從引用的 Microsoft 頁面復制的代碼示例:

#include <stdio.h>
#include <wchar.h>
#include <windows.h>

int main()
{
    // Set output mode to handle virtual terminal sequences
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    if (hOut == INVALID_HANDLE_VALUE)
    {
        return GetLastError();
    }

    DWORD dwMode = 0;
    if (!GetConsoleMode(hOut, &dwMode))
    {
        return GetLastError();
    }

    dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
    if (!SetConsoleMode(hOut, dwMode))
    {
        return GetLastError();
    }

    // Try some Set Graphics Rendition (SGR) terminal escape sequences
    wprintf(L"\x1b[31mThis text has a red foreground using SGR.31.\r\n");
    wprintf(L"\x1b[1mThis text has a bright (bold) red foreground using SGR.1 to affect the previous color setting.\r\n");
    /* ... more examples removed */

    return 0;
}

顯然此解決方案僅適用於 Windows,但運行system("cls")也是不可移植的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM