签名算术

时间:2014-02-26 20:17:43

标签: c++ implicit-conversion

我正在运行这段代码,我得到的输出值为(转换为十六进制)0xFFFFFF93和0xFFFFFF94。

#include <iostream>

using namespace std;

int main()
{
    char x = 0x91;

    char y = 0x02;

    unsigned out;
    out = x + y;

    cout << out << endl;
    out = x + y + 1;
    cout << out << endl;
}

我对这里的算法感到困惑。是因为out中的所有高位都默认为1吗? 当我将类型转换为int时,我得到的答案为(在int中)-109和-108。知道为什么会这样吗?

4 个答案:

答案 0 :(得分:4)

所以这里有很多事情要发生。一, char 可以是签名未签名,在您的情况下,它是签名。两项任务将右侧转换为左侧的类型。使用正确的警告标志会有所帮助,clang标有-Wconversion标志警告:

warning: implicit conversion changes signedness: 'int' to 'unsigned int' [-Wsign-conversion]
out = x + y;
    ~ ~~^~~

在这种情况下,要进行此转换,它基本上会将unsigned max + 1添加或减去要转换的数字。

我们可以使用limits header

看到相同的结果
#include <limits>

//....
std::cout << std::hex <<  (std::numeric_limits<unsigned>::max() + 1) + (x+y) << std::endl ;
//...

结果是:

ffffff93

作为参考,draft C++ standard部分5.17 分配和复合赋值运算符表示:

  

如果左操作数不是类类型,则表达式被隐式转换(第4节)到左操作数的cv-unqualified类型。

4.7 积分转换下的第4条说:

  

如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(模2n,其中n是用于表示无符号类型的位数)。 [注意:在二进制补码表示中,此转换是概念性的,并且位模式没有变化(如果没有截断)。 - 后注]

相当于添加或减去UMAX + 1

答案 1 :(得分:2)

普通char通常也代表签名类型!由于C语法的兼容性原因,这未进一步指定,并且可能依赖于编译器实现。通过明确指定signed / unsigned关键字,您始终可以使其具有独特的签名算术行为。

尝试替换像这样的字符定义

unsigned char x = 0x91;
unsigned char y = 0x02;

获得您期望的结果!

查看完整的示例here

答案 2 :(得分:0)

负数在内部表示为2的补码,因此,它们的第一位是1.当您使用十六进制(并以十六进制打印)时,有效位显示为1,导致您显示的数字。

答案 3 :(得分:0)

C ++没有指定char是否为signed or unsigned。这里它们是有符号的,所以当它们被提升为int时,使用负值,然后将其转换为unsigned。使用或转换为unsigned char