C++ 理解无符号数的行为

C++ 理解无符号数的行为,c++,c,unsigned,C++,C,Unsigned,我的目标是有一个无符号int值的有序升序列表,我使用sub_func选择哪个更大 sub_func返回值是int,因为我想比较所有数字中哪一个更大,它可以正常工作,但是,当我定义无符号int的最大值(0xffffff==-1)时,我遇到了一个问题。我想了解更多关于无符号数字的信息。我该如何解决这个问题 我有以下代码: #define p_max (0xffffffff) uint32 a = p_max; uint32 b = 20; int sub_func(uint32 a, uint32

我的目标是有一个无符号int值的有序升序列表,我使用
sub_func
选择哪个更大

sub_func
返回值是
int
,因为我想比较所有数字中哪一个更大,它可以正常工作,但是,当我定义无符号int的最大值(
0xffffff==-1
)时,我遇到了一个问题。我想了解更多关于无符号数字的信息。我该如何解决这个问题

我有以下代码:

#define p_max (0xffffffff)
uint32 a = p_max;
uint32 b = 20;

int sub_func(uint32 a, uint32 b) 
{
    return (b - a);
}
retrun是21,我希望它最大值是20,它是负数,我的返回类型是负数


但是,我总是看到一个正数。我不想看到的是,如何解决这个问题?

不要将
int
uint
混合使用,除非确实需要,因为最大值不同,因为符号将使用一位

根据您最近的评论,您可以返回0或1,然后决定添加到tail/back或head/front

uint32 sub_func(uint32 a, uint32 b)  
{
    if( a > b )
        return 0;
    else
        return 1;
}
如果要返回true或false,也可以使用bool数据类型。根据比较和返回数据类型调整函数返回代码。

(假设
uint32
为32位无符号整数类型)

b-a
是类型为
uint32
的表达式,因为两个操作数都属于该类型。由于标准定义了
uint32
的环绕行为,其值为21


您正在将其分配给一个
int
类型,因此返回值。

第一,相同类型的
有符号的
无符号的
存储在相同大小的相同空间中(例如
有符号的字符
无符号的字符
存储在1字节上)。因此,对于有符号的
,一半可能值用于存储正值,另一部分可能值用于存储负值。对于无符号
,所有可能的值仅适用于正值:

  • 签名字符
    :-127到127
  • 无符号字符
    :0到255
要计算负数,最常用的方法是“两个补”。要存储-1:

  • 使用值1:0x01
  • 反转它:0xFE
  • 添加1:0xFF
因此,-1在有符号上下文中存储为255在无符号上下文中存储

每个人都会说:不要把有符号和无符号混为一谈

或者,如果您确实需要,请使用更大的大小来计算签名,并且要小心:

std::uint32_t a;
std::uint32_t b;

std::int64_t = static_cast<std::int64_t>(b) - static_cast<std::int64_t>(a)
std::uint32\u t a;
标准:uint32_t b;
std::int64\u t=静态强制转换(b)-静态强制转换(a)

8位和16位大小数据的示例:

您所要求的是不可能的

20 - 0xfffffff = -4294967275
不可由int表示,仅限于范围
[-21474836482147483647]


两个无符号的差需要33位

我刚刚用VC2013测试了这一点,编译器将这些值视为有符号整数,因此得到了21!这是拆解:-

int sub_func(uint32 a, uint32 b)
{
00B813C0  push        ebp
00B813C1  mov         ebp, esp
00B813C3  sub         esp, 0C0h
00B813C9  push        ebx
00B813CA  push        esi
00B813CB  push        edi
00B813CC  lea         edi, [ebp - 0C0h]
00B813D2  mov         ecx, 30h
00B813D7  mov         eax, 0CCCCCCCCh
00B813DC  rep stos    dword ptr es : [edi]
return (b - a);
00B813DE  mov         eax, dword ptr[b]
00B813E1  sub         eax, dword ptr[a]
}
00B813E4  pop         edi
00B813E5  pop         esi
00B813E6  pop         ebx
00B813E7  mov         esp, ebp
00B813E9  pop         ebp
00B813EA  ret

由于有符号32位整数的限制为[-21474836482147483647],它无法保存减法结果,因为它超出了限制。您可以选择64位数据类型来保存减法结果。我在VisualStudio上测试了以下代码

#define p_max 0xffffffff

unsigned int a = p_max;
unsigned int b = 20;

signed long long sub_func() 
{
    return ((signed long long)b - (signed long long)a);
}

int main()
{
    signed long long x = sub_func();
}

将结果存储在
int
中并不妨碍使用
无符号
算法进行减法运算

减去两个
uint32
始终会生成类型为
uint32
的结果。如果减法的数学结果为负,则使用模运算产生一个介于
0
和无符号类型可以表示的最大值之间的值

您已使用该事实从
-1
获取
0xFFFFFFFF
。它与减法的结果一样有效

20-0xfffffff
给出的值为
-4294967275
。模
0x100000000
(a
uint32
可以表示的最大值,加上
1
)是
21
0x15
)<代码>21
转换为
int
仍然是
21

产生负值的一种方法是避免使用
无符号
变量进行减法,例如

int sub_func(uint32 a, uint32 b) 
{
    return (a > b) ? 1 : ((a < b) ? -1 : 0));
}
int sub_func(uint32 a,uint32 b)
{
返回值(a>b)?1:((a
在下面的代码中,问题是为什么nResult会是21

#define p_max (0xffffffff)
uint32 a = p_max;
uint32 b = 20;

void main()
{
    int nResult = b - a;
}
您正在尝试计算:

0000 0000 0000 0001 0100
-
1111111111111111111111111111111111111111111111111

这实际上被计算为加法

1
(2的
1111111111111111111111111111111111111111
)到

0000 0000 0001 0100

=
0000 0000 0001 0101


结果是21,不考虑符号,因为它是由两个uint32操作生成的。因此,即使您将结果值强制转换为带符号的int,它也不会做出任何更改,因为它已经是一个正值。

如果
a
false
,为什么不使用标准方法返回
true
?想想当
a=b=max
时的情况,您需要一个更宽的有符号类型,例如C++11的
long
,它至少是64位。我想要返回值,这对我的进一步编码很重要。
无符号
值不能为负。嗯,当这两个值之间的差值大于
0x7fffffff
时,您的计划是什么?您确定需要有符号的差值吗?你的+/-或+1/0/-1不够吗?你的无符号字符和有符号字符不是颠倒过来了吗?另外,在C++14之前,有符号字符可以从-127到+127。所以,如果我将p_max声明为0x0fffffff,这会起作用吗?@invicur这是一个解决方案是的,将
无符号
限制为
有符号
的最大值