理解无符号数的行为

时间:2016-03-10 09:22:10

标签: c++ c unsigned

我的目标是有一个unsigned int值的排序升序列表,我使用sub_func来选择哪一个更大。

sub_func返回int,因为我想比较哪一个对于它工作正常的所有数字都更大但是,当我定义unsigned int的最大值时,我有一个问题是( 0xffffffff == -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 - MAX,这将是负数,我的返回类型是负数。

但是,我认为它总是一个正数。我不想要的,如何解决这个问题?

8 个答案:

答案 0 :(得分:5)

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

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

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

答案 1 :(得分:2)

不要混用intuint ,除非确实需要,因为最大值不同,因为一位将用于签名。

根据您的最新评论,您可以返回0或1,然后决定添加到尾部/背部或头部/前部。

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

如果要返回true或false,也可以使用bool数据类型。根据比较和返回数据类型调整函数返回码。

答案 2 :(得分:1)

相同类型的Frist,signedunsigned存储在相同大小的相同空间中(例如signed charunsigned char存储在1个字节上)。因此,对于signed,一半可能的值用于存储正值,另一部分可能的值用于存储负值。对于unsigned,所有可能的值仅适用于正值:

  • signed char: - 127到127
  • unsigned char: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)

8位和16位大小数据的示例:http://coliru.stacked-crooked.com/a/38076c588de3907d

答案 3 :(得分:1)

你所要求的是不可能的。

20 - 0xfffffff = -4294967275

,无法用int表示,仅限于范围[-2147483648,2147483647]

两个无符号的差异需要33位!

答案 4 :(得分:1)

您将结果存储在int中这一事实并不妨碍使用unsigned算法完成减法。

减去两个uint32总会产生uint32类型的结果。如果减法的数学结果为负,则使用模运算产生0与无符号类型可表示的最大值之间的值。

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

20 - 0xfffffff的值为-4294967275。该模0x100000000uint32可以表示的最大值加上1)是210x15)。转换为21的{​​{1}}仍为int

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

unsigned

答案 5 :(得分:0)

由于有符号的32位int的限制是[-2147483648,2147483647],因此它不能保持减法的结果,因为它超出了限制。您可以使用64位数据类型来保存减法结果。我在Visual studio上测试了下面的代码。

$myusername = "myusername";
$mypassword = "mypassword";
$site_url = "https:// my site url"; 
$cookiefile = "cookie_filename.txt";
$uagent = "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US....;
$postDatas = 'username='.$myusername.'&password='.$mypassword;
//----------1st request start---------
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$site_url);
curl_setopt($ch, CURLOPT_USERAGENT, $uagent);
curl_setopt($ch, CURLOPT_POST, 1); 
curl_setopt($ch, CURLOPT_POSTFIELDS, $postDatas); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
$res = curl_exec($ch);
curl_close ($ch);
//----------1st request end---------
//----------2nd request start---------
$meee = explode("jsessionid=",str_replace("Content-Length:","",$res));
$sessId = explode(" ",trim($meee[1]));
$postDatas2 = $postDatas.'&jsessionid='.trim($sessId[0]);
 $headers_curl = array(
    "Accept-Encoding: .....",
    "Accept-Language: .....",
    "Accept: .....",
    "Set-Cookie: SESSIONIDS=".trim($sessId[0])."",
    "Path=....",
    "Cache-Control: max-age=0",
  );
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,"https:// my 2nd url");
curl_setopt($ch, CURLOPT_USERAGENT, $uagent);
curl_setopt($ch, CURLOPT_POST, 1); 
curl_setopt($ch, CURLOPT_POSTFIELDS, $postDatas2); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiefile);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiefile);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers_curl);
curl_setopt($ch, CURLOPT_REFERER, "https://my refer url");
curl_exec($ch);
//----------2nd request end--------
//----------3rd request start---------
curl_setopt($ch, CURLOPT_URL,"https:// my 3rd url");
curl_setopt($ch, CURLOPT_USERAGENT, $uagent);
curl_setopt($ch, CURLOPT_POST, 1); 
curl_setopt($ch, CURLOPT_POSTFIELDS, $postDatas2); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiefile);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiefile);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers_curl);
curl_setopt($ch, CURLOPT_REFERER, "https://......");
$checkResult = curl_exec($ch);
//----------3rd request end---------
preg_match_all('/<td width.*value="(.*)<\/form>/s',$checkResult,$chkData3);
preg_match_all('/value=.*?(.*)|">/',$chkData3[0][0],$checkKey);
$checkKey[1] = 
preg_replace('/[^a-zA-Z0-9_ %\[\]\.\(\)%&-]/s', '', $checkKey[1]);
//--------------end--------------------

答案 6 :(得分:0)

在以下代码中,问题是为什么 nResult 21

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

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

您正在尝试计算:

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

实际上计算为添加

11111 1111 1111 1111 1111 1111 1111 1111的2'补码)

0000 0000 0000 0000 0000 0000 0001 0100

= 0000 0000 0000 0000 0000 0000 0001 0101

结果是21并且没有考虑符号,因为它是由两个uint32的操作产生的。因此即使将结果值转换为signed int也不会进行任何更改,因为它已经是正值。

答案 7 :(得分:-1)

我刚用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