hui-shao 发表于 2022-8-30 22:16

【技能分享】为C语言控制台终端启用彩色支持(无需第三方软件)

### 前言

提到在控制台输出彩色文字,大家都会想到使用“ANSI转义序列”(`ESC` `\x1b` `\033`)

但自带的 cmd、Powershell 等终端并不能直接识别这样的序列,而是将其作为普通字符输出,非但没有美观效果,而且会让终端看起来很乱。

在此,本文给出了一种解决方案——虚拟终端序列。为C语言控制台程序开启该特性后,即可完美实现彩色输出。

### 效果图

使用之后的效果是这样的(cmd):



### 开工

#### 简要介绍

> 虚拟终端序列是控制字符序列,可在写入输出流时控制游标移动、控制台颜色和其他操作。 在输入流上也可以接收序列,以响应输出流查询信息序列,或在设置适当模式时作为用户输入的编码。

> 序列的行为基于 VT100 和派生终端仿真器技术,尤其是 xterm 终端仿真器。

——摘自 Microsoft

默认情况下,这个模式是关闭的,因此需要通过代码开启。(注意 Win7 系统可能不适用)

#### 参考代码

Step1,构建一个函数来启用虚拟终端序列特性。

新建一个 `print.c` ,这里面是开启特性的关键代码:

```c
#include "print.h"


/*!
* 为传统控制台启用色彩支持
*/
DWORD enableColorful(void)
{
#if PRINT_COLORFUL
    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();
    }
#endif
    return 0;
}

```

然后新建一个 `print.h` 用于声明上面的函数,以及设置常用颜色的宏定义:

```c
#ifndef PRINT_H
#define PRINT_H

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

DWORD enableColorful(void);

//* 配置 */
#define PRINT_COLORFUL 1// 是否启用彩色

//* 颜色定义 */
#define COLOR_GRAY "\033[37m"
#define COLOR_GREEN "\033[32m"
#define COLOR_YELLOW "\033[33m"
#define COLOR_DARKGRAY "\033[30m"
#define COLOR_BLACK "\033[30m"
#define COLOR_NOCOLOR "\033[0m"
#define COLOR_DEEPBLUE "\033[34m"
#define COLOR_RED "\033[31m"

#endif // PRINT_H

```

Step2,在需要启用彩色的控制台中调用此函数即可。

示例都在代码里啦,注释也很丰富~

`main.c`:

```c
#include "print.h"

int main()
{
    enableColorful(); // 开启彩色支持
   
    // 使用示例
    printf(COLOR_GREEN "INFO: 这是一条提示信息\n" COLOR_NOCOLOR);
    printf(COLOR_RED "ERROR: 这是一条错误信息\n" COLOR_NOCOLOR);
   
    // 接下来的示例来自微软
    // 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");
    wprintf(L"\x1b[mThis text has returned to default colors using SGR.0 implicitly.\r\n");
    wprintf(L"\x1b[34;46mThis text shows the foreground and background change at the same time.\r\n");
    wprintf(L"\x1b[0mThis text has returned to default colors using SGR.0 explicitly.\r\n");
    wprintf(L"\x1b[31;32;33;34;35;36;101;102;103;104;105;106;107mThis text attempts to apply many colors in the same command. Note the colors are applied from left to right so only the right-most option of foreground cyan (SGR.36) and background bright white (SGR.107) is effective.\r\n");
    wprintf(L"\x1b[39mThis text has restored the foreground color only.\r\n");
    wprintf(L"\x1b[49mThis text has restored the background color only.\r\n");
    return 0;
}
```

到此,新技能成功 Get √。

总体上来说,使用还是很方便而且简单的,欢迎各位小伙伴交流。

### 其它知识

#### ANSI 转义码格式

基本格式如下:

```
\x1b[(文字装饰);(颜色代码):
```

文字装饰:

| 0    | 1    | 3    | 4      |
| ---- | ---- | ---- | ------ |
| 正常 | 加粗 | 背景 | 下划线 |

颜色代码:

| 基本 8 色 | 基本高对比色 | xterm 的 256色 |
| --------- | ------------ | -------------- |
| 30 ~ 37   | 90 ~ 97      | 0 ~ 256      |

关于更多的颜色可以参考一下 Wiki:(https://en.wikipedia.org/wiki/ANSI_escape_code#Colors)

#### 一些值得参考的资料

1. [浅析 \x1B\(https://www.cnblogs.com/goloving/p/15015053.html)

2. Microsoft官方文档:[控制台虚拟终端序列](https://docs.microsoft.com/zh-cn/windows/console/console-virtual-terminal-sequences)

iawyxkdn8 发表于 2022-8-31 09:29

牛逼,大佬!

sRGB 发表于 2022-8-31 09:57

薛定谔消失的弦 发表于 2022-8-31 14:13

这个好像和bash一样使用\0xb[xxm

hui-shao 发表于 2022-8-31 16:41

薛定谔消失的弦 发表于 2022-8-31 14:13
这个好像和bash一样使用\0xb

是的,但是直接printf的话无法使用,要用 API 临时开启一下虚拟终端特性

zhaoqingdz 发表于 2022-9-2 21:13

这个功能很小众!但很有创意!感谢楼主分享!

TJSCer 发表于 2022-9-4 10:21

最近正在研究终端彩色输出,感谢分享

TengA 发表于 2022-11-13 10:47

之前找好久都没找到,楼主强啊

nihz 发表于 2022-12-16 08:24

windows下,直接使用system("cls") 就可以启用了。
页: [1]
查看完整版本: 【技能分享】为C语言控制台终端启用彩色支持(无需第三方软件)