在x86_64 CentOS 7 GCC 4.8.5 C ++ 11上:
#include <iostream>
int main()
{
std::cout << ((ssize_t)1 - (size_t)5) << '\n';
}
// Output: 18446744073709551612
可是:
#include <iostream>
int main()
{
std::cout << ((ssize_t)1 - (unsigned int)5) << '\n';
}
// Output: -4
在i686 CentOS 6 GCC 4.8.2 C ++ 11上,他们都给4294967292
所以我必须这样做:
#include <iostream>
int main()
{
std::cout << ((ssize_t)1 - (ssize_t)5) << '\n';
}
// Output: -4
一个非常人为的例子,很明显,我理解我在整体推广规则中根据平台/实现定义的类型等价来命中各种条款,但在周四我的大脑无法解开他们进行了严格的评估。
导致这些结果的标准规则的确切顺序是什么?
答案 0 :(得分:16)
免责声明:我参考C ++ 17最新草案N4606第5段第11段。我引用和引用的措辞包含在paragraph 9 of N3337中,它实际上与C ++ 11标准相同,并且在C ++ 14的FD中也是如此,所以这个答案也适用于这些标准
假设ssize_t
和size_t
排名相同,在第一种情况下,[expr]/(11.5.5)适用:
否则,两个操作数都应转换为对应的无符号整数类型 带有符号整数类型的操作数的类型。
1将转换为ssize_t
的无符号版本,该版本应为size_t
- 因此无符号下溢,且值为2 sizeof(size_t)*8
- 4。
对于你的第二种情况,假设unsigned
的等级小于ssize_t
的等级,而后者可以保留所有以前的值;见[expr]/(11.5.4):
否则,如果带有符号整数类型的操作数的类型可以表示的所有值 具有无符号整数类型的操作数的类型,具有无符号整数类型的操作数应为 转换为带有符号整数类型的操作数的类型。
即。 5
将转换为ssize_t
,因此我们会得到否定结果。如果ssize_t
的排名不高于unsigned
,我们会得到2 sizeof(unsigned)*8
-4;如果相反ssize_t
无法保存所有unsigned
的值,我们会再次得到否定结果,因为我们会看到前面提到的(11.5.5)。