溢出已签名/未签名的分配及其结果

时间:2013-07-31 17:20:46

标签: c++ unsigned signed integer-overflow

我正在阅读Stroustrup的书“The C ++ Programming Language 4th edition”,并且有三个关于溢出赋值的问题(特别是签名/未签名的字符,如本书所示)。首先,根据标准的5/4段:

  

如果在评估表达式期间,结果不是   在数学上定义或不在可表示值的范围内   它的类型,行为未定义

(除非目标变量是无符号的 - 在这种情况下结果明确定义)。但这个定义是否也与作业有关?

因为在我看来书中有很多相反的陈述,所有内容都在第6章。第一章对应上述段落,但以下评论并非如此:

  

可以为每个类型自由分配三种char类型的变量   其他。但是,为signed char分配过大的值仍然存在   未定义。例如:

void g(char c, signed char sc, unsigned char uc)
{
    c = 255; //implementation-defined if plain chars are signed and have 8 bits
    c = sc; //OK
    c = uc; //implementation-defined if plain chars are signed and if uc's value is too large
    sc = uc; //implementation-defined if uc's value is too large
    uc = sc; //OK: conversion to unsigned
    sc = c; //implementation-defined if plain chars are unsigned and if c's value is too large
    uc = c; //OK: conversion to unsigned
}

第一个问题:因为分配一个太大的值是UB,那么为什么评论说它是实现定义的呢?

接下来我们有以下示例:

  

具体而言,假设char是8位:

signed char sc = -160;
unsigned char uc = sc; //uc == 116 (because 256-160==116)
cout << uc; //print 't'

第二个问题:除了第一个作业被认为是UB这个事实之外,作者用什么公式来提出116?在我的测试中,uc的值为96。

最后一句话:

  

整数可以转换为另一种整数类型。如果   目标是signed,如果可以,则值不变   以目的地类型表示;否则,价值是   实现定义:

     

signed char sc = 1023; //implementation-defined

     

合理的结果是127和-1。

第三个问题:再次,除了这与前面关于UB所说的相反的事实之外,为什么可能的结果是127和-1?我想它与一个和两个补码有关,但使用的精确公式是什么?

1 个答案:

答案 0 :(得分:-1)

1)定义的实现是“一类UB” - 换句话说,它仍然是UB,只是实现负责解释它是如何工作的,而不是“你根本不能依赖这个操作” 。因此,如果您指定了超出范围的char值,则仍允许编译器爆炸您的计算机。但实现也可以定义“它将其切换为8位等效值”。

2)我的计算器上256 - 160 = 96。我敢打赌它也在你的身上。也许作者有一个不同的计算器?或者它是最后一刻从-150变为-160的那些事情之一,它忘了改变最终结果。

3)由于它是“实施定义”,它最终几乎可以成为任何东西。由于该值为十六进制的0x3ff,我们可以将0xff或0x7f想象成合理的值,具体取决于实现决定如何做到这一点。我希望MOST编译器将使用0xff值。