2016-02-04 439 views
2

我使用的编译器是g++ (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4.signed,unsigned和float类型之间的转换如何工作?

我编译我的程序使用以下命令:

g++ -std=c++11 -pedantic -Wall program.cpp 

程序没有。 1:

#include <iostream> 
using namespace std; 

int main() { 
    unsigned int b; 
    b = -54; 
    cout << b << endl; 
    return 0; 
} 

该程序打印4294967242,这是我的预期值,因为这样的话,当我们指定外的范围内的值,以无符号类型的变量,所以结果是模数的其余部分。

该程序没有。 2:

#include <iostream> 
using namespace std; 

int main() { 
    unsigned int b; 
    b = 54.1234; 
    cout << b << endl; 
    return 0; 
} 

该程序打印54,并且这也行,因为所存储的值是小数点之前的部分,和所述franctional部分被截断。

该程序没有。 3:

#include <iostream> 
using namespace std; 

int main() { 
    unsigned int b; 
    b = -54.1234; 
    cout << b << endl; 
    return 0; 
} 
编译期间

在这里,我得到警告“溢出隐不断转换”。

程序打印0.为什么这样?我认为它会完成小数部分的截断(如程序2),然后存储模数除法的结果(如程序1)。

但是,如果我写程序没有。 4 .:

程序号码。 4.

#include <iostream> 
using namespace std; 

int main() { 
    unsigned int b; 
    float k = -54.1234; 
    b = k; 
    cout << b << endl; 
    return 0; 
} 

然后我没有得到任何警告,我得到的结果(由我预期)4294967242,这是模除法的结果。

如果有人能解释给我,我将不胜感激。

为什么程序没有。 3的行为与程序编号不同。 4?编译程序编号时,为什么不发出警告? 1,但编译程序时我得到一个。 3.?

+0

程序3是唯一一个具有恒定转换和整数溢出的程序。显然这就是编译器的工作原理。我可以仔细阅读语言规范的文本,试着找出可能发生的原因,但看起来你比我有更多的时间。如果我猜测,这可能是未定义的行为,这就是为什么你不首先编写程序3的原因。 –

+0

一般来说,依靠一致的溢出行为来正确执行程序操作可能不是一个好主意,除非你的问题域特别需要这样的一点点操作。 –

+0

由于x86指令集中有一个怪癖,当从浮点到整数的转换发生溢出时,观察到的行为可能非常令人惊讶。请参阅http://blog.frama-c.com/index.php?post/2013/10/09/Overflow-float-integer –

回答

1

将浮点数转换为整数时,C和C++将浮点数转向零。四舍五入的结果必须在目标类型中表示。

因此,对于32位无符号整数,转换保证给出正确的结果,如果-1 < x < 2^32。对于较小的数字,没有保证。由于-1和0之间的数字必须四舍五入为零,而数字-1和较小的数字没有要求,所以如果编译器检查是否x < 0并在此情况下给出结果0,这并不奇怪。 (编译器可能检查是否x < 1并给出0的结果;这也处理非常小的正数)。

+0

说“较小”而不是“较小”会更好地表达意义,因为“较小”也用来表示较小的幅度。 – chux

4

根据标准(§[conv.fpint])。

浮点类型的值可以转换为整数类型的prvalue。转换截断;也就是说,小数部分被丢弃。 如果截断值无法在目标类型中表示,则行为未定义。

因此,您的-54.1234被截断为-54。既然这不能用无符号表示,你会得到未定义的行为。

相关问题