简体   繁体   English

理解无符号数的行为

[英]understanding the behaviour of unsigned numbers

My goal is have a sorted ascending list of unsigned int values, I use the sub_func to choose which one is greater. 我的目标是有一个unsigned int值的排序升序列表,我使用sub_func来选择哪一个更大。

The sub_func return is int because I want to compare which one is greater for all the numbers it works fine but, I have a problem when I define the max value of unsigned int which is ( 0xffffffff == -1 ). sub_func返回是int因为我想比较哪一个对于它工作正常的所有数字都更大但是,当我定义unsigned int的最大值( 0xffffffff == -1 )时,我遇到了问题。 I want to understand more on unsigned numbers over here. 我想更多地了解这里的无符号数字。 How would I solve this problem? 我该如何解决这个问题?

I have the following code: 我有以下代码:

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

int sub_func(uint32 a, uint32 b) 
{
    return (b - a);
}

The retrun is 21, where as I want it to be 20 - MAX, which will be negative and my return type is negative. 后退是21,我希望它是20 - MAX,这将是负数,我的返回类型是负数。

But, i see it always a positive number. 但是,我认为它总是一个正数。 which I dont want, how to workaround this? 我不想要的,如何解决这个问题?

(Assuming uint32 is a 32 bit unsigned integral type). (假设uint32是32位无符号整数类型)。

b - a is an expression with type uint32 since both operands are of that type. b - a是类型为uint32的表达式,因为两个操作数都属于该类型。 Due to the standards-defined wrap-around behaviour of uint32 , it will have the value of 21. 由于uint32的标准定义环绕行为,它的值为21。

You are assigning that to an int type, hence the return value. 您将其分配给int类型,因此返回值。

Don't mix int and uint unless it is really required as the max value is different because one bit will be used for sign. 除非确实需要,否则不要混用intuint ,因为最大值不同,因为一个位将用于符号。

Based on your latest comment, you can return 0 or 1 and then decide to add to tail/back or head/front. 根据您的最新评论,您可以返回0或1,然后决定添加到尾部/背部或头部/前部。

uint32 sub_func(uint32 a, uint32 b)  
{
    if( a > b )
        return 0;
    else
        return 1;
}

You can also use bool data type if you want to return true or false. 如果要返回true或false,也可以使用bool数据类型。 Adjust your function return code based on the comparison and return data type. 根据比较和返回数据类型调整函数返回码。

Frist, signed and unsigned of same type are stored in same a space of same size (for example signed char and unsigned char are stored on 1 byte). 相同类型的Frist, signedunsigned存储在相同大小的相同空间中(例如signed charunsigned char存储在1个字节中)。 So, for signed , half of possible values are used to store positive values and the other part of possible values are used to store negative values. 因此,对于有signed ,一半可能的值用于存储正值,另一部分可能的值用于存储负值。 For unsigned , all possible values are for positive values only : 对于unsigned ,所有可能的值仅适用于正值:

  • signed char : -127 to 127 signed char :-127到127
  • unsigned char : 0 to 255 unsigned char :0到255

To calculate a negative, the most use solution is "two's complement". 要计算负数,最常用的解决方案是“二进制补码”。 To store -1 : 存储-1:

  • use of value of 1 : 0x01 使用值1:0x01
  • invert it : 0xFE 反转它:0xFE
  • add 1 : 0xFF 加1:0xFF

So, -1 is store in signed context as 255 in unsigned context. 因此,-1在无符号上下文中以有符号上下文存储为255。

It's for that every one say : don't mix signed and unsigned! 这是为了每个人都说: 不要混合签名和未签名!

Or if you really need that, use a greater size to calculate signed and be carefull : 或者,如果您确实需要,请使用更大的尺寸来计算签名并小心

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

std::int64_t = static_cast<std::int64_t>(b) - static_cast<std::int64_t>(a)

Example with 8 and 16 bits size data : http://coliru.stacked-crooked.com/a/38076c588de3907d 8位和16位大小数据的示例: http//coliru.stacked-crooked.com/a/38076c588de3907d

What you are asking is impossible. 你问的是不可能的。

20 - 0xfffffff = -4294967275

which is not representable by an int, restricted to the range [-2147483648,2147483647] . 不能用int表示,限制在[-2147483648,2147483647]范围内。

The difference of two unsigned requires 33 bits ! 两个无符号的差异需要33位!

The fact you are storing the result in an int does not prevent the subtraction being done using unsigned arithmetic. 将结果存储在int事实不会阻止使用unsigned算术进行减法。

A subtraction of two uint32 always produces a result which is of type uint32 . 减去两个uint32总是产生一个类型为uint32的结果。 If the mathematical result of the subtraction is negative, modulo arithmetic is used to produce a value between 0 and the maximum that the unsigned type can represent. 如果减法的数学结果为负,则使用模运算产生介于0和无符号类型可表示的最大值之间的值。

You have used that fact to get 0xFFFFFFFF from -1 . 您已使用该事实从-1获取0xFFFFFFFF It works equally with results of subtraction. 它与减法结果同样有效。

20 - 0xfffffff gives a value of -4294967275 . 20 - 0xfffffff给出的值为-4294967275 That modulo 0x100000000 (the maximum a uint32 can represent, plus 1 ) is 21 ( 0x15 ). 模数0x100000000uint32可以表示的最大值加1 )为210x15 )。 21 converted to int is still 21 . 21转换为int仍然是21

One way to produce a negative value is to avoid doing subtraction using unsigned variables, such as; 产生负值的一种方法是避免使用unsigned变量进行减法,例如;

int sub_func(uint32 a, uint32 b) 
{
    return (a > b) ? 1 : ((a < b) ? -1 : 0));
}

As the limit for a signed 32-bit int is [-2147483648,2147483647], it cannot hold the result of subtraction as it is out of the limit. 由于有符号的32位int的限制是[-2147483648,2147483647],因此它不能保持减法的结果,因为它超出了限制。 You can go for a 64-bit data type to hold the result of subtraction. 您可以使用64位数据类型来保存减法结果。 I tested the below code on Visual studio. 我在Visual Studio上测试了下面的代码。

#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();
}

In the following code, the question is why the nResult would be 21 . 在下面的代码中,问题是为什么nResult将是21

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

void main()
{
    int nResult = b - a;
}

You are trying to calculate: 你试图计算:

0000 0000 0000 0000 0000 0000 0001 0100 - 1111 1111 1111 1111 1111 1111 1111 1111 0000 0000 0000 0000 0000 0000 0001 0100 - 1111 1111 1111 1111 1111 1111 1111 1111

which is actually computed as adding 实际上计算为添加

1 (2's complement of 1111 1111 1111 1111 1111 1111 1111 1111 ) to 1 (2的补充1111 1111 1111 1111 1111 1111 1111 1111 )至

0000 0000 0000 0000 0000 0000 0001 0100 . 0000 0000 0000 0000 0000 0000 0001 0100

= 0000 0000 0000 0000 0000 0000 0001 0101 = 0000 0000 0000 0000 0000 0000 0001 0101

The result is 21 and there is no consideration of sign since it's produced by two uint32's operation. 结果是21并且没有考虑符号,因为它是由两个uint32的操作产生的。 So it doesn't make any change even if you cast the result value to signed int, because it's already a positive value. 因此,即使将结果值转换为signed int也不会进行任何更改,因为它已经是正值。

I just tested this with VC2013 and the compiler is treating the values as signed integers, hence getting 21! 我刚刚用VC2013对它进行了测试,编译器将值视为有符号整数,因此得到21! Here's the disembly:- 这是装备: -

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM