超过64位时未定义的行为

时间:2012-09-09 23:00:34

标签: c++ 64-bit overflow

我编写了一个将十进制数转换为二进制数的函数。我输入我的十进制数作为long long int。它适用于小数字,但我的任务是确定计算机如何处理溢出,所以当我输入(2 ^ 63) - 1时,函数输出十进制值为9223372036854775808,二进制值等于-954437177。当我输入2 ^ 63这是64位机器无法保持的值时,我得到警告:整数常量太大而无符号且十进制常数仅在ISO C90和十进制输出中无符号值为负2 ^ 63,二进制数为0.我使用gcc作为编译器。这个结果是否正确?

代码如下:

#include <iostream>
#include<sstream>
using namespace std;
int main()
{
long long int answer;
long long dec;
string binNum;
stringstream ss;
cout<<"Enter the decimal to be converted:"<< endl;;
cin>>dec;
cout<<"The dec number is: "<<dec<<endl;
while(dec>0)
{
     answer = dec%2;
     dec=dec/2;
     ss<<answer;
     binNum=ss.str();
}
cout<<"The binary of the given number is: ";
for (int i=sizeof(binNum);i>=0;i--){
     cout<<binNum[i];}
return 0;
    }

2 个答案:

答案 0 :(得分:7)

首先,“在64位计算机上”是没有意义的:无论计算机如何,long long都保证至少64位。如果可以将现代C ++编译器压缩到Commodore 64或Sinclair ZX80上,或者就KIM-1而言,long long仍然至少为64位。这是 C ++标准给出的与机器无关的保证。

其次,指定一个太大的值与“溢出”相同。

使这个问题变得有趣的唯一因素是存在差异。并且该标准对这两种情况的处理方式不同。对于使用整数值初始化有符号整数的情况,如果需要,将执行转换,如果无法表示值,则使用实现定义的效果,...

  

C ++11§4.7/ 3 :   “如果目标类型已签名,则该值如果可以在目标类型(和位字段宽度)中表示,则不会更改;否则,该值是实现定义的“

而对于例如一个乘法产生一个无法用参数类型表示的值,效果是未定义的(例如,甚至可能崩溃)......

  

C ++11§5/ 4 :   “如果在评估表达式期间,结果未在数学上定义或未在其类型的可表示值范围内,则行为未定义。”

关于代码I,我在编写上面的代码后才发现它,但看起来它确实会产生足够大数量的溢出(即未定义行为)。将您的数字放在vectorstring中。请注意,您也可以使用bitset来显示二进制数字。

哦,KIM-1。没有多少人熟悉它,所以这是一张照片:

KIM-1 single-board computer

据报道,尽管键盘有些受限制,但据报道它非常好。

答案 1 :(得分:1)

这种代码的改编产生了您需要的答案。你的代码很容易用错误的顺序产生答案。十进制值123,1234567890,12345678901234567的详尽测试表明它工作正常(Mac OS X 10.7.4上的G ++ 4.7.1)。

#include <iostream>
#include<sstream>
using namespace std;
int main()
{
    long long int answer;
    long long dec;
    string binNum;
    cout<<"Enter the decimal to be converted:"<< endl;;
    cin>>dec;
    cout<<"The dec number is: "<<dec<<endl;
    while(dec>0)
    {
        stringstream ss;
        answer = dec%2;
        dec=dec/2;
        ss<<answer;
        binNum.insert(0, ss.str());
//      cout << "ss<<" << ss.str() << ">>   bn<<" << binNum.c_str() << ">>" << endl;
    }
    cout<<"The binary of the given number is: " << binNum.c_str() << endl;

    return 0;
}

测试运行:

$ ./bd
Enter the decimal to be converted:
123
The dec number is: 123
The binary of the given number is: 1111011
$ ./bd
Enter the decimal to be converted:
1234567890
The dec number is: 1234567890
The binary of the given number is: 1001001100101100000001011010010
$ ./bd
Enter the decimal to be converted:
12345678901234567
The dec number is: 12345678901234567
The binary of the given number is: 101011110111000101010001011101011010110100101110000111
$ bc
bc 1.06
Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 
obase=2
123
1111011
1234567890
1001001100101100000001011010010
12345678901234567
101011110111000101010001011101011010110100101110000111
$

  

当我用64位机器的最大值编译它时,没有任何东西显示我的二进制值。

$ bc 1.06
Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 
2^63-1
9223372036854775807
quit
$ ./bd
Enter the decimal to be converted:
9223372036854775807
The dec number is: 9223372036854775807
The binary of the given number is: 111111111111111111111111111111111111111111111111111111111111111
$

如果您为可以表示的最大值选择较大的值,则所有投注均已关闭;您可能会从cin >> dec;返回0并且代码无法正确处理0.


前奏

问题中的原始代码是:

#include <iostream>
using namespace std;
int main()
{
    int rem,i=1,sum=0;
    long long int dec = 9223372036854775808; // = 2^63     9223372036854775807 =  2^63-1
    cout<<"The dec number is"<<dec<<endl;
    while(dec>0)
    {
        rem=dec%2;
        sum=sum + (i*rem);
        dec=dec/2;
        i=i*10;
    }
    cout<<"The binary of the given number is:"<<sum<<endl;
    return 0;
}

我对前面的代码进行了分析:

  

对于64位数字中的每个位位置,您将普通int变量i乘以10。鉴于i可能是32位数量,您将遇到有符号整数溢出,这是未定义的行为。即使i是128位数量,也不足以准确处理所有可能的64位数字(例如2 63 -1)。