如果我在与字符进行比较之前没有明确将 int 转换为字符,这有关系吗?

Does it matter if I don't explicitly cast an int to a char before comparison with a char?

本文关键字:字符 转换 int 有关系 比较 如果      更新时间:2023-10-16

在比较 int 和 char 时,我应该显式转换其中一个,还是让编译器为我做?有关系吗?为什么?

例如

int i = 113;
char c = 'q';
if (static_cast<char>(i) == c)
cout << "equal";
// OR
if (i == c)
cout << "equal";

实际上,在某些情况下,由于积分提升以及将int显式转换为char会截断更高的字节这一事实,它确实很重要。 基本上,如果您尝试比较两种不同大小的类似数字的类型,则可以通过某些规则将它们转换为某种"通用类型",这通常足以"适合"两种类型。但是,如果您进行显式转换,则可能会丢失一些信息。

请考虑以下代码:

#include <iostream>
using namespace std;
int main() {
int i = 113;
char c = 'q';
cout << (static_cast<char>(i) == c) << endl; // 1
cout << (i == c) << endl; // 1
i += 0x100; // i is now 369, but lower byte is 113.
cout << (static_cast<char>(i) == c) << endl; // 1
cout << (i == c) << endl; // 0
return 0;
}

当您显式将int转换为char时,较高的字节通常会被截断(如注释中所述,它是实现定义的)。但是,当您将intchar进行比较时,后者会自动提升为int,然后比较两个ints

在这种特殊情况下,您可以避免显式强制转换。然而,正如这个答案中提到的,这样做在意识形态上并不总是正确的,因为在标准库中存储的字符通常是非负数int(例如0..255),而不是char,可以根据编译器/平台进行签名(例如-128..127)。如果比较中有非 ASCII 字符,这将导致潜在问题。

因此,如果您绝对确定永远不需要非 ASCII,则可以避免显式强制转换。但如果不是这种情况(或者如果你想养成一个好习惯),最好在与int进行比较之前考虑一下约定并将char转换为unsigned char

i == static_cast<unsigned char>(c)

示例中的强制转换应该通过unsigned charcharint


char值表示为int的非常非常强的约定,特别是对于像isalpha这样的函数,是负char值表示为转换为unsigned char的值,一个严格的非负值。

对于遵守此最常见约定的代码,条件在

if (static_cast<char>(i) == c)

做完全错误的事情。

例如,对于 8 位字节和 2 的补码符号char类型(这是迄今为止最常见的),i值 128 表示char值 -128。然后,上述条件可能会错误地生成false因为当值不适合强制转换为签名类型时,您具有实现定义的行为。然后,演员阵容完全不必要地引入了一个错误。

相反,正确的条件通过绕道将负值转换为严格的非负值来将该char提升为int

using Byte = unsigned char;
//...
if( i == static_cast<Byte>( c ) )

sizeof(int)= 1 的情况下,即使char是无符号类型,此条件仍然有效。


标准库的char分类函数对否定参数具有未定义的行为,特殊值EOF除外。

所以电话

isalpha( c )

通常具有未定义的行为,因为通常char是有符号类型,并且可能会出现负值,例如拉丁语 1 编码的'Å'.

相反,它应该是

using Byte = unsigned char;
//...
isalpha( static_cast<Byte>( c ) )