0

这是隔离问题的代码:

#include <iostream>
#include <windows.h>

using namespace std;

int main() {
  SetConsoleOutputCP(CP_UTF8);
  _wsystem(L"echo pure ascii, naïveté");
  COORD pos = {0,0};

  TCHAR* attempt1 = new TCHAR[14];
  DWORD charnum1;
  ReadConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), attempt1, 14, pos, &charnum1);
  wcout << endl << "charnum1: " << charnum1 << ", attempt1: " << attempt1 << endl;
  wcout << "GetLastError: " << GetLastError();

  TCHAR* attempt2 = new TCHAR[16];
  DWORD charnum2;
  ReadConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), attempt2, 16, pos, &charnum2);
  wcout << endl << "charnum2: " << charnum2 << ", attempt2: " << attempt2 << endl;
  wcout << "GetLastError: " << GetLastError();

  system("pause > nul");
}

输出是:

pure ascii, naïveté

charnum1: 14, attempt1: pure ascii, na
GetLastError: 0
charnum2: 0, attempt2: x >
GetLastError: 0

第一次尝试正常,但是当函数尝试使用非 ASCII 字符读取位置时,它什么也不返回,也没有指示任何错误。现在要做什么 ?

4

1 回答 1

2

警告:在我的系统上,CP_UTF8 不可用,因此当我运行您的代码时,echo命令会导致“系统无法写入指定的设备”。

但是,如果我删除SetConsoleOutputCP()调用并将其保留在默认代码页 437 中,我会正确显示字符串。

请注意,有单独的读取和写入代码页。我尝试了 437、850、1252 和 28591 的各种组合——后两个或多或少映射到 Unicode 的前 255 个代码点。如果 CP_UTF8 对您有效,请通过调用SetConsoleCP(CP_UTF8).

请注意,ReadConsoleOutputCharacter()不会在最后一个读取字符之后放置空值,因此当您输出该 TCHAR 数组时,您的代码中会出现问题:您无法保证它是以空值结尾的并且它可能会崩溃。(另外,您不会删除分配的 TCHAR 数组。)所以,我将分配行更改为:

TCHAR attempt1[] = L"____________________";  // 20 underscores

其中(没有调用SetConsoleOutputCP())产生了这个:

charnum1: 14, attempt1: pure ascii, na______
charnum2: 16, attempt2: pure ascii, na∩v____

第二行中倒数第二个字形不是“n”,而是代码页 437 中的字符 0xEF。“ï”是 Unicode 中的字符 0xEF。这里发生的是,从控制台读取了正确的代码点 (0xEF),但流输出继续使用 437 代码页。流输出根据流的语言环境设置选择其字符,而不是在控制台中设置的代码页。

我不知道为什么当控制台的 READ 代码页仍然是 437 时从控制台读取所需的代码点值。我也很困惑为什么,如果我SetConsoleOutputCP(1252)(或 28591),echo命令的输出看起来像是在使用 CP 437 :pure ascii, na∩vitΘ

于 2012-06-06T00:18:23.357 回答