C++中有符号和无符号之间的转换

7
考虑以下 C++ 代码:
#include <cstdio>

using namespace std;

int main()
{
    int ia = -5;
    unsigned int uia = ia;
    char ca = -5;
    unsigned char uca = ca;

    printf("%d\n", (ia == uia));
    printf("%d\n", (ca == uca));

    return 0;
}

输出结果为:
1
0

当从 signed 转换为 unsigned 时,我不理解 intchar 之间的区别是什么?

你能否给我讲解一下呢?


4
“char”很奇怪,它与“signed char”有所不同。 - Pubby
这个SO问题的最后一个答案提供了一些关于三种char类型的信息;char、signed char和unsigned char都是不同的。 - Dave Newman
3个回答

7

当从有符号转换为无符号时,它们的行为是相同的。不同之处在于==比较的行为。对于int/unsigned,它的行为与预期相同,但是当您比较两个较小的类型时,它们都会首先提升为int。因此,发生的情况是-5的无符号8位表示和-5都被提升为int,然后进行比较。这些显然是不同的,并且未通过比较。


如果您能提到推广的价值观,那就太好了。 - Nawaz
char类型的值-5的二进制表示为11111011。而unsigned char的二进制表示也是相同的(11111011)。但是当一个char被转换为int时,编译器应该保持charint的值相同。因为char是-5,所以int也应该是-5。然后将一个unsigned char转换为int时,它的值也应该保持不变。unsigned char的值为251,所以int为251。这就是为什么char的-5不等于unsigned char的-5。 - Expressway Retrograding

1

好的,这种不一致行为的实际原因是 char 和 unsigned 的底层提升。我想更具体地解释一下。

首先,当比较 int 和 unsigned int 变量时,它们的类型并不重要,因为无论它们是什么类型,在内存中它们都有相同的二进制表示,这就是 == 运算符关心的内容。

然而,当 == 应用于 char 和 unsigned char 变量时,它们将首先扩展为相应的 32 位整数类型,它们如何扩展是不一致性的关键。由于 ca 是一个 char,它将通过 MOVSX 扩展到带有符号位(sign-bit)的整数,而 uca 将仅通过 MOVZX 扩展,只填充 0。因此,它们现在具有不一致的二进制表示。

汇编代码揭示了这个真相。

    int b1 = ia == uia;
000613E5  mov         eax,dword ptr [ia]  
000613E8  xor         ecx,ecx  
000613EA  cmp         eax,dword ptr [uia]  
000613ED  sete        cl  
000613F0  mov         dword ptr [b1],ecx  
    int b2 = ca == uca;
000613F3  movsx       eax,byte ptr [ca]  
000613F7  movzx       ecx,byte ptr [uca]  
000613FB  xor         edx,edx  
000613FD  cmp         eax,ecx  
000613FF  sete        dl  
00061402  mov         dword ptr [b2],edx 

-3

有符号类型可以是负数也可以是正数。而无符号类型的值更高,但不能为负。

因此,无符号整数的最大值为4,294,967,296,最小值为0。

而有符号整数的范围为-2,147,483,648到2,147,483,648。

希望这能帮助您理解有符号和无符号类型之间的区别。

当您想避免一个值为负数时,这个特性会很有用。例如,引用数组或者需要仅使用正数大值而不需要负数时,以避免使用长整型。


1
这并没有真正解决有关char的问题。 - Dave Newman

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