C/C++控制台文字颜色设置全攻略
前言
写了这么多年控制台程序,是不是早就看腻了那千篇一律的黑底白字?其实让控制台输出带上颜色并没有想象中那么复杂。今天就来聊聊C/C++里各种改颜色的方法,顺便把坑都给你排一遍。
需要说明的是:标准C/C++本身没有“颜色”这个概念。所有颜色控制本质上都是调用操作系统提供的接口,或者向终端输出特定的控制字符。所以不同平台的方法是完全不同的。
一、system(“color”) —— 最简单粗暴的方法
这是很多新手最先接触到的方法,因为代码量最少。
用法
#include <windows.h> // 或 <stdlib.h>
int main() {
system("color 0A"); // 背景黑色(0),文字淡绿色(A)
printf("Hello World!\\n");
return 0;
}
color后面跟两个十六进制字符(0-F):第一个是背景色,第二个是文字颜色。
颜色代号对照表:
| 0 | 黑色 | 8 | 灰色 |
| 1 | 蓝色 | 9 | 淡蓝色 |
| 2 | 绿色 | A | 淡绿色 |
| 3 | 湖蓝色 | B | 淡浅绿色 |
| 4 | 红色 | C | 淡红色 |
| 5 | 紫色 | D | 淡紫色 |
| 6 | 黄色 | E | 淡黄色 |
| 7 | 白色 | F | 亮白色 |
致命缺点
system("color")一旦调用,整个控制台的颜色都会被改变,无法做到只让某一行文字变色。而且它本质上是调用系统命令,有性能开销,在一些在线评测环境中甚至可能被禁用。
适合场景:快速测试、小工具、不在乎“一行一种颜色”的情况。
二、SetConsoleTextAttribute —— Windows下最靠谱的方法
Windows控制台原生支持文字颜色控制,SetConsoleTextAttribute是Windows API中专门干这个活的函数。它不需要第三方库,不依赖ANSI转义,在Windows 7及以上版本都能用。
基本用法
#include <windows.h>
#include <iostream>
int main() {
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); // 获取控制台输出句柄
// 设置文字为亮红色
SetConsoleTextAttribute(hOut, FOREGROUND_RED | FOREGROUND_INTENSITY);
std::cout << "这段文字是亮红色" << std::endl;
// 重置为默认白色(三原色全开)
SetConsoleTextAttribute(hOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
std::cout << "回到白色" << std::endl;
return 0;
}
颜色常量说明
SetConsoleTextAttribute的颜色值是通过位掩码组合实现的:
前景色(文字颜色):
- FOREGROUND_RED — 红色
- FOREGROUND_GREEN — 绿色
- FOREGROUND_BLUE — 蓝色
- FOREGROUND_INTENSITY — 高亮(使颜色变亮)
背景色(对应常量):
- BACKGROUND_RED
- BACKGROUND_GREEN
- BACKGROUND_BLUE
- BACKGROUND_INTENSITY
组合方式就是按位或(|)。例如:
- FOREGROUND_RED | FOREGROUND_INTENSITY → 亮红色
- FOREGROUND_RED | FOREGROUND_GREEN → 黄色(红+绿)
- FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE → 白色
注意事项
必须先获取有效句柄,不能硬写0或NULL。建议检查返回值:
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hOut == INVALID_HANDLE_VALUE) return;
颜色不会自动继承。每次输出前都要重新设置,否则后续所有输出都会保持之前的颜色。所以记得在需要的时候重置。
只适用于Windows。在Linux/macOS上这段代码根本编译不过。
封装成函数
实际开发中一般会封装一下:
#include <windows.h>
#include <iostream>
void setColor(WORD color) {
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hOut != INVALID_HANDLE_VALUE) {
SetConsoleTextAttribute(hOut, color);
}
}
int main() {
setColor(FOREGROUND_RED | FOREGROUND_INTENSITY);
std::cout << "红色错误信息" << std::endl;
setColor(FOREGROUND_GREEN | FOREGROUND_INTENSITY);
std::cout << "绿色成功信息" << std::endl;
setColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); // 重置白色
return 0;
}
三、ANSI转义码 —— 跨平台的终极方案
ANSI转义码是一套起源于上世纪70年代的终端控制标准,通过特殊的字符序列来控制文本样式、颜色和光标位置。
在Linux、macOS以及现代终端中,这是最主流的方式。Windows从10版本1511开始也原生支持了,只是默认没开启。
基本语法
在C/C++中,用\\033(八进制)或\\x1b(十六进制)表示转义字符的开头。
基本颜色控制:
std::cout << "\\033[31m" << "红色文字" << "\\033[0m" << std::endl;
// ^^^^^^ ^^^^^^^^ ^^^^^^
// 开始红色 文字内容 重置所有样式
格式说明: \\033[ + 参数 + m
常用参数:
| 0 | 重置所有样式 | 1 | 粗体/高亮 |
| 4 | 下划线 | 7 | 反色 |
| 30-37 | 前景色(黑红绿黄蓝紫青白) | 40-47 | 背景色 |
| 90-97 | 亮前景色 | 100-107 | 亮背景色 |
具体颜色对应:
- 30/40 — 黑色
- 31/41 — 红色
- 32/42 — 绿色
- 33/43 — 黄色
- 34/44 — 蓝色
- 35/45 — 紫色
- 36/46 — 青色
- 37/47 — 白色
示例:
std::cout << "\\033[32m绿色文字\\033[0m" << std::endl;
std::cout << "\\033[1;33m亮黄色加粗\\033[0m" << std::endl; // 多个参数用分号分隔
std::cout << "\\033[41;37m白字红底\\033[0m" << std::endl;
256色模式
除了基本的16色,ANSI还支持256色甚至RGB真彩色。
256色语法:
// 前景色:\\033[38;5;{颜色代码}m
// 背景色:\\033[48;5;{颜色代码}m
std::cout << "\\033[38;5;196m亮红色\\033[0m" << std::endl; // 196是亮红
std::cout << "\\033[38;5;46m亮绿色\\033[0m" << std::endl; // 46是亮绿
256色的范围:
- 0-15:系统标准16色
- 16-231:216色立方(RGB各6级)
- 232-255:24级灰度
Windows下启用ANSI支持
这是最大的坑。 旧版Windows控制台(cmd.exe)默认不解析ANSI转义码。直接输出\\033[31m你会看到满屏的←[31m乱码。
解决方法:手动启用虚拟终端处理模式。
#include <windows.h>
#include <iostream>
int main() {
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD dwMode = 0;
GetConsoleMode(hOut, &dwMode);
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(hOut, dwMode);
// 现在可以愉快地使用ANSI了
std::cout << "\\033[32m绿色\\033[0m" << std::endl;
return 0;
}
注意:这个设置只对当前进程有效,子进程不会继承。而且Windows 7/8完全不支持。
Linux/macOS下直接使用
在Linux和macOS上,终端原生支持ANSI转义码,不需要任何额外配置。
但有一个小细节:如果程序输出被重定向到文件,或者运行在非终端环境(如CI/CD管道),转义码会变成一堆乱码混在日志里。建议用isatty()检测一下:
#include <unistd.h>
if (isatty(STDOUT_FILENO)) {
printf("\\x1b[32m[OK]\\x1b[0m 一切正常\\n");
} else {
printf("[OK] 一切正常\\n"); // 非终端环境不加颜色
}
四、完整代码汇总
下面是一份整合了三种方法的完整示例代码,Windows下优先用SetConsoleTextAttribute,Linux/macOS自动切换到ANSI:
/**
* C/C++ 控制台颜色设置 – 完整示例
* 编译: g++ -std=c++11 console_color.cpp -o console_color
* 支持: Windows (SetConsoleTextAttribute) / Linux/macOS (ANSI)
*/
#include <iostream>
#include <string>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
// ———- 颜色枚举(统一接口) ———-
enum ConsoleColor {
BLACK = 0,
RED,
GREEN,
YELLOW,
BLUE,
MAGENTA,
CYAN,
WHITE,
BRIGHT_RED,
BRIGHT_GREEN,
BRIGHT_YELLOW,
BRIGHT_BLUE,
BRIGHT_MAGENTA,
BRIGHT_CYAN,
BRIGHT_WHITE
};
// ———- Windows 实现 ———-
#ifdef _WIN32
WORD getWinColor(ConsoleColor color) {
switch (color) {
case BLACK: return 0;
case RED: return FOREGROUND_RED;
case GREEN: return FOREGROUND_GREEN;
case YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;
case BLUE: return FOREGROUND_BLUE;
case MAGENTA: return FOREGROUND_RED | FOREGROUND_BLUE;
case CYAN: return FOREGROUND_GREEN | FOREGROUND_BLUE;
case WHITE: return FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
case BRIGHT_RED: return FOREGROUND_RED | FOREGROUND_INTENSITY;
case BRIGHT_GREEN: return FOREGROUND_GREEN | FOREGROUND_INTENSITY;
case BRIGHT_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
case BRIGHT_BLUE: return FOREGROUND_BLUE | FOREGROUND_INTENSITY;
case BRIGHT_MAGENTA:return FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
case BRIGHT_CYAN: return FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
case BRIGHT_WHITE: return FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
default: return FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
}
}
void setConsoleColor(ConsoleColor color) {
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hOut != INVALID_HANDLE_VALUE) {
SetConsoleTextAttribute(hOut, getWinColor(color));
}
}
// ———- Unix/Linux/macOS 实现 ———-
#else
const char* getAnsiColor(ConsoleColor color) {
switch (color) {
case BLACK: return "\\033[30m";
case RED: return "\\033[31m";
case GREEN: return "\\033[32m";
case YELLOW: return "\\033[33m";
case BLUE: return "\\033[34m";
case MAGENTA: return "\\033[35m";
case CYAN: return "\\033[36m";
case WHITE: return "\\033[37m";
case BRIGHT_RED: return "\\033[91m";
case BRIGHT_GREEN: return "\\033[92m";
case BRIGHT_YELLOW: return "\\033[93m";
case BRIGHT_BLUE: return "\\033[94m";
case BRIGHT_MAGENTA:return "\\033[95m";
case BRIGHT_CYAN: return "\\033[96m";
case BRIGHT_WHITE: return "\\033[97m";
default: return "\\033[0m";
}
}
void setConsoleColor(ConsoleColor color) {
// 检测是否为终端环境,避免污染重定向输出
if (isatty(STDOUT_FILENO)) {
std::cout << getAnsiColor(color);
}
}
#endif
// ———- 重置颜色 ———-
void resetColor() {
#ifdef _WIN32
setConsoleColor(WHITE);
#else
if (isatty(STDOUT_FILENO)) {
std::cout << "\\033[0m";
}
#endif
}
// ———- 彩色输出函数 ———-
void colorPrint(const std::string& text, ConsoleColor color) {
setConsoleColor(color);
std::cout << text;
resetColor();
}
// ———- 主函数测试 ———-
int main() {
std::cout << "========== 控制台颜色测试 ==========" << std::endl;
colorPrint("红色文字\\n", RED);
colorPrint("绿色文字\\n", GREEN);
colorPrint("黄色文字\\n", YELLOW);
colorPrint("蓝色文字\\n", BLUE);
colorPrint("紫色文字\\n", MAGENTA);
colorPrint("青色文字\\n", CYAN);
std::cout << "\\n========== 亮色测试 ==========" << std::endl;
colorPrint("亮红色\\n", BRIGHT_RED);
colorPrint("亮绿色\\n", BRIGHT_GREEN);
colorPrint("亮黄色\\n", BRIGHT_YELLOW);
colorPrint("亮蓝色\\n", BRIGHT_BLUE);
std::cout << "\\n========== 混合输出 ==========" << std::endl;
setConsoleColor(RED);
std::cout << "错误";
resetColor();
std::cout << ": 文件未找到" << std::endl;
setConsoleColor(GREEN);
std::cout << "成功";
resetColor();
std::cout << ": 编译完成" << std::endl;
setConsoleColor(YELLOW);
std::cout << "警告";
resetColor();
std::cout << ": 使用了已弃用的API" << std::endl;
return 0;
}
五、各方法对比
| 跨平台性 | ❌ 仅Windows | ❌ 仅Windows | ✅ Linux/macOS/Windows 10+ |
| 是否需要额外头文件 | <windows.h>或<stdlib.h> | <windows.h> | 无(标准C++即可) |
| 能否单独控制某行 | ❌ 整个控制台统一变色 | ✅ 可精确控制每行 | ✅ 可精确控制每行 |
| 性能开销 | 较大(调用外部命令) | 小(直接API调用) | 小(直接输出字符) |
| 学习难度 | ⭐ 极低 | ⭐⭐ 低 | ⭐⭐⭐ 中等 |
| Windows 7兼容 | ✅ | ✅ | ❌ 不支持 |
| Windows 10+兼容 | ✅ | ✅ | ✅(需手动启用VT模式) |
| 支持颜色数量 | 16色 | 16色 | 256色 / 真彩色 |
| 是否支持样式(粗体/下划线) | ❌ | ❌ | ✅ |
| 推荐场景 | 快速测试、Demo | Windows正式项目 | 跨平台项目、现代终端 |
六、常见问题与避坑指南
Q1:为什么我的ANSI转义码在Windows下无效?
因为旧版cmd默认不解析ANSI。要么手动调用SetConsoleMode开启VT模式,要么换用Windows Terminal。如果不想折腾,直接用SetConsoleTextAttribute。
Q2:SetConsoleTextAttribute设置颜色后,后面的输出全变色了?
因为这个API改变的是控制台句柄的属性,会一直生效直到你再次修改。每次输出完记得重置:
SetConsoleTextAttribute(hOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
Q3:在Linux下用ANSI,但输出被重定向到文件时出现了乱码?
因为转义码被当作文本写进文件了。用isatty()判断一下当前是否是终端,不是的话就别输出颜色。
Q4:system("color")和SetConsoleTextAttribute能混用吗?
可以,但不推荐。system("color")会改变整个控制台的默认颜色,而SetConsoleTextAttribute是在这个基础上再做调整。混用容易造成混乱,选一种统一使用就好。
Q5:多线程环境下颜色控制安全吗?
不安全。 颜色状态是全局的,多个线程同时输出时可能互相覆盖。真要线程安全,要么加锁,要么用线程局部缓冲。不过一般小项目不用太纠结这个问题。
结语
总结一下我的建议:
- Windows-only项目:无脑上SetConsoleTextAttribute,稳定可靠,不用折腾。
- 跨平台项目:用ANSI转义码,配合isatty()做环境检测,Windows下记得开启VT模式。
- 随便玩玩:system("color")最省事。
颜色控制说到底就是跟操作系统或终端打交道,搞清楚原理之后其实就那么回事。希望这篇文章能帮你少踩几个坑。






