1

出于某种原因,If/else 语句在 C++ 中对我来说不能正常工作

问题是当变量等于右边 (höger) 时,它不会输出 If 语句,而是继续执行 else 语句。如果我将字母 'ö' 替换为 say 'o' 所以它变成了 'hoger',那么 if 语句将起作用。因此,每当我写下“höger”这个词时,它都不会转到 if 语句,而是会转到 else 语句。但是,如果我使变量等于“hoger”,然后我写“hoger”,它将起作用。如果 If 语句识别它,我怎样才能写出 'höger' 呢?好像瑞典字母不起作用。

我的代码如下所示:

#include <iostream>
#include <string>

using namespace std;


int main() {
    setlocale(LC_ALL,"");


    string test; // Define variabel
    cout << " Höger elle vänster"<<endl; // Right or left
    cin >> test;


    if(test == "höger") { // If right, then output this.

        cout <<"Du valde höger"<<endl;

    } 

    else if(test == "vänster") { // If left, then output this

        cout <<"Du valde vänster"<<endl;

    } else {

        // Do this

    }


}
4

4 回答 4

4

这个问题几乎肯定与编码有关。

C/C++ 语言规范不会自动处理除 7 位 ASCII 以外的任何内容。o-umlaut 字符超出该范围,具体行为取决于源代码文件的编码。

最可能的可能性是 ISO 8859-1、Windows ANSI-1252、UTF-8 或 Windows OEM 850。前两个对这个字符进行相同的编码,但在其他每个中它是不同的。

了解更多有关您正在使用的编码和工具集的信息,可能会提供更具体的诊断和建议。

[顺便说一下,C/C++ 中的 if/else 语句工作得很好,谢谢。]


如果我们暂时假设这是 Windows 和 Visual C++,那么这就是您要处理的内容。

  • 在 Visual Studio 中编写的源代码:代码页 1252。o-umlaut 字符的代码点是 0xf6。
  • 从控制台读取的键盘输入:代码页 850。o-umlaut 字符的代码点是 0x94。

显然不是很好的搭配。但是,Visual Studio 也可以非常愉快地编辑多种编码的源代码文件,包括 UTF-8(带字节标记)、UTF-16(宽字符)和代码页 850。所以:

  • 在 Visual Studio 中编写的源代码:代码页 850。o-umlaut 字符的代码点是 0x94。现在它起作用了。

您还可以使用 CHCP 命令更改控制台的代码页。

  • 将控制台更改为 CHCP 1252 即可。

标准要求编译器在读取源代码时的行为必须与执行字符集保持一致。参见 n3797 S2.2.5:

字符文字或字符串文字中的每个源字符集成员,以及字符文字或非原始字符串文字中的每个转义序列和通用字符名称,都将转换为执行字符集的相应成员

S2.3/3:

基本执行字符集和基本执行宽字符集应分别包含基本源字符集的所有成员,加上表示警报、退格和回车的控制字符,加上一个空字符(分别为空宽字符),其表示全为零。对于每个基本执行字符集,成员的值应该是非负的并且彼此不同。在源和执行基本字符集中,上述十进制数字列表中 0 之后的每个字符的值都应比前一个字符的值大 1。执行字符集和执行宽字符集分别是基本执行字符集和基本执行宽字符集的实现定义的超集。

n3797 S2.14.3/1:

不以 u、U 或 L 开头的字符文字是普通字符文字,也称为窄字符文字。包含在执行字符集中可表示的单个 c-char 的普通字符文字具有 char 类型,其值等于执行字符集中 c-char 编码的数值。

n3297 S2.14.5/6:

不以编码前缀开头的字符串文字是普通的字符串文字,并使用给定的字符进行初始化。

执行字符集是实现定义的。微软关于 C 编译器实现定义行为的声明在这里:http: //msdn.microsoft.com/en-us/library/hx3yt8af.aspx。[我找不到一个单独的 C++,所以我认为这适用于两者。]

The source character set is the set of legal characters that can appear in source files. For Microsoft C, the source character set is the standard ASCII character set.

对不起语言律师的东西,但这说明 MSVC 编译器独立于语言环境/编码并实现 8 位 ASCII,未指定代码页。显然,标准库函数可能需要知道用于各种目的的编码,但那是另一回事了。


最后一点,Microsoft C 编译器可以追溯到大约 30 年前,比 Windows 早。在代码页 850 中编写源代码并使其在控制台上正确运行始终是可能的,但需要仔细处理扩展(8 位)字符。许多人仍然这样做。这里的问题是用 Windows-Ansi 或 Unicode 编写的源代码和来自 OEM (cp850) 控制台的键盘输入。更改其中任何一个以使其正常工作。

于 2014-04-06T11:24:10.760 回答
1

实际上,这个问题只会在 Windows 中表现出来,所以我假设是 Windows。

那么问题是C++狭义扩展执行字符集(1)(编码)与控制台窗口使用的编码不匹配。“窄”是指char类型。“执行字符集”是 C++ 标准采用的正式术语,指的是假定用于存储在可执行文件中的文本的编码。编译器将源代码文字转换为此编码。它还假设用于与任何外部编码的转换,例如与控制台编码的转换。

      在此处输入图像描述

使用 Visual C++ 时,无论源代码编码如何,窄编码始终是Windows ANSI (2),除非您欺骗了编译器。假设您使用的是 Visual C++,那么这就是您知道的一种编码。

默认情况下,控制台窗口中的编码是用于原始 IBM PC 的编码,在您的情况下可能是代码页 850(原始 IBM PC 英语代码页 437 的西欧变体)。运行 Windows 命令解释器cmdWindows-key+ R、type cmd、OK)。键入chcp以检查当前代码页。键入chcp 1252以切换到 Windows ANSI Western,这可能是您计算机上的 Windows ANSI 代码页。运行您的程序 [.exe] 文件,例如通过输入其完整路径,或转到其目录并仅输入其名称,例如

[H:\开发\测试\0046]
> cl /nologo /EHsc /GR encoding.cpp /Fe:b.exe
编码.cpp

[H:\开发\测试\0046]
> chcp & b
活动代码页:850
 Höger elle vänster
höger
                             这里没有输出,没有比较相等。
[H:\开发\测试\0046]
> chcp 1252
活动代码页:1252

[H:\开发\测试\0046]
>
 Höger elle vänster
豪格
杜瓦尔德霍格

[H:\开发\测试\0046]
> _

... 其中cl(原始“Lattice C”的缩写)是 Visual C++ 编译器。

您可以通过运行来更永久地更改控制台代码页regedit,转到此注册表项:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage

并在右窗格的列表中双击名为OEMCP(原始设备制造商代码页的缩写,指 IBM PC)的值,将其更改为 1252,或更一般地为与该值相同的ACP值,然后重新启动机器.

哦,还需要将控制台窗口字体更改为TrueType 字体,例如 Lucida Console,因为默认是(模拟的)位图字体,只能在原始控制台代码页上正常工作。您可以右键单击控制台窗口标题以获取菜单,选择[默认],并配置默认字体、大小、颜色等。更改不会影响当前控制台窗口,但它们将应用于以后的控制台窗口,除了对于那些已经单独配置的(3)

这种控制台窗口配置的替代方法是使用Console2程序。如果这样做,那么在 Windows 7 及更高版本中请务必使用 64 位版本。否则有些事情,例如调用 64 位程序的链接,将无法正常工作。


总结一下,你可以

  • 从命令解释器运行程序(chcp用于更改代码页),或

  • 如上所述,更永久地更改控制台代码页。

无论哪种情况,将控制台窗口字体更改为 TrueType 字体都是一个好主意——是的,这会影响功能,而不仅仅是外观。

注意微软的其他荒谬之处:在 Windows 7 及更高版本中,默认情况下在控制台窗口中使用的“系统”字体实际上是在幕后,具有数千个字形的 TrueType 字体,但它用于模拟旧的 16 位 Windows 位图字体, 有同样愚蠢的限制,所以你仍然必须更改为其他一些 TrueType 字体......


(1)参见 C++11 标准 §2.3/3。

(2) “Windows ANSI”取决于 Windows 配置,始终是GetACPAPI 函数指定的代码页。实际上,此函数从上面引用的注册表键/值中获取其值。但是,这在很大程度上是无证的。

(3)在 Windows XP 中,Windows 会询问您是否要保存单个控制台窗口配置。从 Windows Vista 开始,它会毫无疑问地保存,也没有任何信息表明它已保存。没有用于删除此类已保存配置的用户界面,但可以通过以编程方式更改快捷方式文件和/或通过注册表编辑来删除它们,但这是一种不切实际且脆弱的解决方案。

于 2014-04-06T11:38:56.800 回答
0

我对您的代码所做的唯一更改如下:

// setlocale(LC_ALL, "");
char *l = setlocale(LC_ALL, NULL);
cout << "Current Locale: " << l << endl;

因为我没有“ISO”键盘布局,所以我使用Alt 代码键入我需要的字符。以下是我用于不同代码页的组合键。

  • 第一次运行我必须在代码页 437Alt中输入+246
  • 第二次运行,Alt+148用于Windows-1252

下面是我在执行之间更改代码页时的输出 程序输出

于 2014-04-06T14:23:21.780 回答
0

当您的 IDE 编译它时,问题似乎是源文件的编码。如果您使用的是 Visual Studio,您可以像这样更改编码设置:

这里

于 2016-01-15T14:06:39.597 回答