为什么这个表达式是不合格的?

时间:2016-12-01 13:53:26

标签: c++ c++11 language-lawyer

在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

一个非常人为的例子,很明显,我理解我在整体推广规则中根据平台/实现定义的类型等价来命中各种条款,但在周四我的大脑无法解开他们进行了严格的评估。

导致这些结果的标准规则的确切顺序是什么?

1 个答案:

答案 0 :(得分:16)

免责声明:我参考C ++ 17最新草案N4606第5段第11段。我引用和引用的措辞包含在paragraph 9 of N3337中,它实际上与C ++ 11标准相同,并且在C ++ 14的FD中也是如此,所以这个答案也适用于这些标准

假设ssize_tsize_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)。