2

我正在阅读 Stroustrup 的书“C++ 编程语言第 4 版”,并且有关于溢出分配的三个问题(特别是签名/未签名字符,如书中所举例说明的那样)。首先,根据标准 5/4 段:

如果在计算表达式期间,结果未在数学上定义或不在其类型的可表示值范围内,则行为未定义

(除非目标变量是无符号的——在这种情况下结果是明确定义的)。但是这个定义是否也适用于分配?

因为在我看来,书中有很多相反的陈述,都在第 6 章。第一个对应于上述段落,但以下注释没有:

这三种类型的变量char可以自由地相互分配。但是,将太大的值分配给 asigned 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,那么为什么评论说它是实现定义的?

接下来我们有以下示例:

具体来说,假设 achar为 8 位:

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

第二个问题:除了第一个作业应该是UB之外,作者究竟使用了什么公式来得出116?在我的测试中,uc得到了 96 的值。

最后一句话:

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

signed char sc = 1023; //implementation-defined

合理的结果是 127 和 -1。

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

4

1 回答 1

-1

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

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

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

于 2013-07-31T17:31:56.913 回答