我正在阅读 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,那么为什么评论说它是实现定义的?
接下来我们有以下示例:
具体来说,假设 a
char
为 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?我想这与一个和两个的补码有关,但是使用的精确公式是什么?