我正在阅读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?我想它与一个和两个补码有关,但使用的精确公式是什么?
答案 0 :(得分:-1)
1)定义的实现是“一类UB” - 换句话说,它仍然是UB,只是实现负责解释它是如何工作的,而不是“你根本不能依赖这个操作” 。因此,如果您指定了超出范围的char
值,则仍允许编译器爆炸您的计算机。但实现也可以定义“它将其切换为8位等效值”。
2)我的计算器上256 - 160 = 96。我敢打赌它也在你的身上。也许作者有一个不同的计算器?或者它是最后一刻从-150变为-160的那些事情之一,它忘了改变最终结果。
3)由于它是“实施定义”,它最终几乎可以成为任何东西。由于该值为十六进制的0x3ff,我们可以将0xff或0x7f想象成合理的值,具体取决于实现决定如何做到这一点。我希望MOST编译器将使用0xff值。