C++控制台国际象棋程序Unicode棋子显示为问号的问题排查
问题
我正在开发一款C++控制台国际象棋游戏,计划使用Unicode棋子符号显示棋盘,但黑后(♕)、白后(♛)等Unicode棋子符号均显示为问号(?)。
以下是我的代码:
#include "ChessGame.h" #include <iostream> #include <locale> #include <codecvt> #include <iomanip> #include <Windows.h> using namespace std; const wchar_t* pieces[7] = { L"♕", L"♙", L"♖", L"♘", L"♗", L"♕", L"♔" }; const wchar_t* blackPieces[7] = { L"♛", L"♟", L"♜", L"♞", L"♝", L"♛", L"♚" }; ChessGame::ChessGame() : whiteTurn(true) { board = { { {-5, -3, -4, -7, -6, -4, -3, -5}, {-1, -1, -1, -1, -1, -1, -1, -1}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 1, 1, 1, 1, 1, 1, 1, 1}, { 5, 3, 4, 7, 6, 4, 3, 5} } }; } void ChessGame::run() { SetConsoleOutputCP(CP_UTF8); wcout.imbue(locale("en_US.UTF-8")); while (true) { printBoard(); wcout << (whiteTurn ? L"White's move." : L"Black's move.") << endl; wcout << L"Enter your move (e.g., e2 e4): "; string start, end; cin >> start >> end; int startX = start[0] - 'a'; int startY = 8 - (start[1] - '0'); int endX = end[0] - 'a'; int endY = 8 - (end[1] - '0'); if (isMoveValid(board[startY][startX], startX, startY, endX, endY)) { processMove(startX, startY, endX, endY); whiteTurn = !whiteTurn; } else { wcout << L"Invalid move. Try again." << endl; } } } void ChessGame::printBoard() { wcout << L" A B C D E F G H" << endl; wcout << L" +-----------------+" << endl; for (int y = 0; y < 8; ++y) { wcout << 8 - y << L" | "; for (int x = 0; x < 8; ++x) { int piece = board[y][x]; if (piece > 6 || piece < -6) { wcout << L"?" << L" "; continue; } if (piece > 0) wcout << pieces[piece] << L" "; else if (piece < 0) wcout << blackPieces[-piece] << L" "; else wcout << L". "; } wcout << L"| " << 8 - y << endl; } wcout << L" +-----------------+" << endl; wcout << L" A B C D E F G H" << endl; } bool ChessGame::isMoveValid(int piece, int startX, int startY, int endX, int endY) { if (startX < 0 || startX >= 8 || startY < 0 || startY >= 8 || endX < 0 || endX >= 8 || endY < 0 || endY >= 8) { cerr << "Index out of range!" << endl; return false; } if (board[startY][startX] == 0) return false; if (whiteTurn && piece < 0) return false; if (!whiteTurn && piece > 0) return false; return true; } void ChessGame::processMove(int startX, int startY, int endX, int endY) { board[endY][endX] = board[startY][startX]; board[startY][startX] = 0; }
运行结果:
A B C D E F G H +-----------------+ 8 | ♛ ♞ ♝ ? ♚ ♝ ♞ ♛ | 8 7 | ♟ ♟ ♟ ♟ ♟ ♟ ♟ ♟ | 7 6 | . . . . . . . . | 6 5 | . . . . . . . . | 5 4 | . . . . . . . . | 4 3 | . . . . . . . . | 3 2 | ♙ ♙ ♙ ♙ ♙ ♙ ♙ ♙ | 2 1 | ♕ ♘ ♗ ? ♔ ♗ ♘ ♕ | 1 +-----------------+ A B C D E F G H
尽管已通过SetConsoleOutputCP(CP_UTF8)设置控制台输出为UTF-8,并为wcout注入locale("en_US.UTF-8"),且使用的终端(如Windows Terminal或Visual Studio输出控制台)支持UTF-8,但棋盘仍显示问号而非正确的Unicode棋子符号。其他文本显示正常,仅Unicode棋子符号存在问题。
请问遗漏了什么?如何确保控制台正确渲染Unicode字符?该如何解决此问题使棋子符号正常显示?
解决方案
1. 修复数组索引越界问题
你的核心问题是棋子编号与数组索引不匹配导致越界访问:
- 棋盘初始化中,白方国王编号是7,黑方国王编号是-7,但你的
pieces和blackPieces数组长度仅为7(索引0-6),访问pieces[7]会触发越界,直接输出问号。 - 同时数组索引对应逻辑混乱:比如
pieces[0]被赋值为白后,但代码中棋子编号从1开始使用。
修正步骤:
- 调整棋子编号与数组索引的对应关系,扩展数组长度到8(索引0留空,匹配1-7的棋子编号):
// 索引0留空,1=兵,3=车,4=马,5=象,6=后,7=王 const wchar_t* pieces[8] = { L"", L"♙", L"", L"♖", L"♘", L"♗", L"♕", L"♔" }; const wchar_t* blackPieces[8] = { L"", L"♟", L"", L"♜", L"♞", L"♝", L"♛", L"♚" };
- 修正棋盘初始化的编号顺序,确保国王(7/-7)、后(6/-6)的位置正确:
ChessGame::ChessGame() : whiteTurn(true) { board = { { {-5, -3, -4, -6, -7, -4, -3, -5}, // 黑方:象、车、马、后、王、马、车、象 {-1, -1, -1, -1, -1, -1, -1, -1}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 1, 1, 1, 1, 1, 1, 1, 1}, { 5, 3, 4, 6, 7, 4, 3, 5} // 白方:象、车、马、后、王、马、车、象 } }; }
2. 完善控制台Unicode输出配置
在Windows平台,仅设置代码页不够,需要额外配置终端模式:
void ChessGame::run() { // 同时设置输入、输出代码页为UTF-8 SetConsoleOutputCP(CP_UTF8); SetConsoleCP(CP_UTF8); // 启用虚拟终端处理,提升Unicode渲染兼容性 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); DWORD mode = 0; GetConsoleMode(hOut, &mode); SetConsoleMode(hOut, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); wcout.imbue(locale("en_US.UTF-8")); // ... 原有代码 }
另外,统一使用宽字符输出,把cerr改为wcerr避免编码混合:
wcerr << L"Index out of range!" << endl;
3. 确保源码与编译环境编码一致
- 将源码文件保存为不带BOM的UTF-8编码;
- 在Visual Studio中,项目属性 -> 常规 -> 字符集选择
使用多字节字符集,或添加编译选项/utf-8强制使用UTF-8编译。
内容的提问来源于stack exchange,提问作者AlexMcKenze
相关产品推荐
相关产品推荐

