在Visual Studio 2008中输入俄文字母错误会抛出控制台异常

3

可能是重复问题:
我在Visual Studio 2008中看不到俄语字母

我正在尝试从控制台输入用俄语字母编写的符号。这是代码:

#include <iostream>
#include <windows.h>
#include <locale.h>
using namespace std;

void main(){
    char c;
    setlocale(LC_ALL,"rus");
    cout << "Я хочу видеть это по-русски!" << endl;
    cin >> c;
    cout << c;
}

我输入了 'ф',但它输出的是 'д'。我尝试使用


char buf[2];
char str[2];
str[0] = c;
str[1] = '\0';
OemToAnsi(buf, str);

但是我有

+       str 0x0015fef4 "¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ф¦¦¦¦d §"    char [2]
+       buf 0x0015ff00 "¦¦¦ф¦¦¦¦d §"    char [2]

然后我遇到了一个错误,运行时检查失败#2——变量'str'周围的堆栈已被破坏。


.cpp文件的编码是什么?它可以在“另存为”对话框中的“高级保存选项”下看到。 - Ilmo Euro
1
也许你需要使用宽字符和字符串,以及流对象的宽字符版本(例如 std::wcoutstd::wcin)? - Some programmer dude
@Ilmo 欧洲编码西里尔字母(Windows)- 代码页1251 - Maria
@Joachim Pileborg 我尝试使用wcin,但没有帮助。现在它将'ф'视为L'д'。 - Maria
这绝对不是一个重复的问题,因为第一个答案已经解释了。 - Artem Pelenitsyn
显示剩余2条评论
3个回答

2
我假设您的设置是将源文件保存为cp1251(Cyrillic Windows),并将控制台设置为使用cp866(Cyrillic DOS)。 (这将是俄语Windows版本的默认设置。)您遇到的问题似乎是,像您这样设置区域设置会导致输出从cp1251转换为cp866,但不会导致输入的反向转换。因此,当您读取字符时,程序会得到cp866表示。当输出这个cp866表示时,它会被错误地视为cp1251表示,并转换为cp866,导致“ф”到“д”的转换。
我认为转换只是基于C语言环境库(CRT)进行的,但我不知道如何启用类似的输入转换。有不同的选项可以使程序正常工作:
- 在回显输入数据之前手动将其从cp866转换为cp1251。 - 将`setlocale(LC_ALL,"rus")`替换为调用`SetConsoleCP(1251); SetConsoleOutputCP(1251);`,这将改变控制台的行为(更改将持续整个控制台生命周期而不是程序生命周期)。 - 使用UTF-16的Windows API替换cin和cout。微软的标准库实现强制使用传统编码,在Windows上引起各种类似问题。所以最好完全避免使用它。
下面是第二个选项的示例:
#include <iostream>
#include <clocale>

#include <Windows.h>

void main(){
    char c;
    SetConsoleCP(1251);
    SetConsoleOutputCP(1251);

    std::cout << "Я хочу видеть это по-русски!\n";
    std::cin >> c;
    std::cout << c;
}

假设源代码采用cp1251编码,则输出将显示正确,输入的字符“ф”不会被转换为“д”。

我执行了SetConsoleCP(866); SetConsoleOutputCP(866);,它可以工作。但是现在,如果我不使用setlocale(LC_ALL,“rus”),输出将不正确。 - Maria
我认为问题在于源代码是cp1251编码,需要使用setlocale(LC_ALL,"rus")将字符串从cp1251转换为cp866,以匹配对SetConsoleOutputCP(866)的调用。 - bames53

0
const int N = 34;
const char DosABC[N] = "абвгдеёжзийклмнопрстуфхцчшщъыьэюя";
const char WinABC[N] = " ЎўЈ¤Ґс¦§Ё©Є«¬­®Їабвгдежзийклмноп";

std::string ToDosStr(std::string input)
{
    std::string output = "";
    bool Ok;
    for (unsigned i = 0; i < input.length(); i++)
    {
        Ok = false;
        for (int j = 0; j < N; j++)
            if (input[i] == WinABC[j])
            {
                output += DosABC[j];
                Ok = true;
            }
            if (!Ok)
                output += input[i];
    }
    return output;
} 

我做到了,而且它也起作用了,但欢迎大家寻找更简单的答案。


http://www.cplusplus.com/reference/clibrary/cstring/strxfrm/ 可能 可以工作,我不确定。 - Ilmo Euro
@Ilmo Euro 我测试了i,但它不起作用 :( - Maria

0

区域设置可能有误。请尝试

setlocale(LC_ALL, ""); 

这将区域设置为“默认值,即从操作系统获取的用户默认 ANSI 代码页”。


不,它没有帮助。当我尝试时,它不能正确显示第一个cout。 - Maria

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接