我正在阅读 Stroustrup 的书“C++ 编程语言第 4 版”,并且有三个关于溢出赋值的问题(特别是有符号/无符号字符,如书中所示)。首先,按照标准的5/4段落:
If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined.
(除非目标变量是无符号的 - 在这种情况下结果已明确定义)。但是这个定义是否也适用于作业?
因为我觉得书中有很多相反的说法,都在第6章。第一个对应上述段落,但以下评论不是:
Variables of the three
char
types can be freely assigned to each other. However, assigning a too large value to asigned char
is still undefined. For example: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,那么为什么评论说它是实现定义的?
接下来我们有如下例子:
To be concrete, assume that a
char
is 8 bits:signed char sc = -160; unsigned char uc = sc; //uc == 116 (because 256-160==116) cout << uc; //print 't'
第二个问题:除了第一个赋值应该是UB之外,作者到底用了什么公式得出116?在我的测试中,uc
得到了 96 的值。
最后一句话:
An integer can be converted to another integer type. If the destination is
signed
, the value is unchanged if it can be represented in the destination type; otherwise, the value is implementation-defined:
signed char sc = 1023; //implementation-defined
Plausible results are 127 and -1.
第三个问题:同样,除了这与之前关于UB所说的相反之外,为什么可能的结果是127和-1?我猜它与一个和两个的补码有关,但使用的精确公式是什么?
最佳答案
1) 实现定义的是“一类UB”——换句话说,它仍然是UB,只是实现负责解释它是如何工作的,而不是“你不能完全依赖这个操作” .因此,如果您分配超出范围的 char
值,编译器仍然可以破坏您的计算机。但实现也可以定义“将其截断为 8 位等效值”。
2) 256 - 160 = 96 在我的计算器上。我敢打赌它也在你身上。也许作者有不同的计算器?或者它是最后一分钟从 -150 更改为 -160 的那些东西之一,它忘记了更改最终结果。
3) 因为它是“实现定义的”,所以它几乎可以是任何东西。由于该值为十六进制的 0x3ff,我们可以将 0xff 或 0x7f 想象为合理的值,具体取决于实现决定如何做到这一点。我预计大多数编译器将使用 0xff 值。
关于c++ - 溢出的签名/未签名分配及其结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17976878/