一个补码架构上的负零行为?

Vin*_*ent 9 c++ standards integer ones-complement c++11

在一个补码架构上考虑以下代码:

int zero = 0;
int negzero = -0;
std::cout<<(negzero < zero)<<std::endl;
std::cout<<(negzero <= zero)<<std::endl;
std::cout<<(negzero == zero)<<std::endl;
std::cout<<(~negzero)<<(~zero)<<std::endl;
std::cout<<(1 << negzero)<<std::endl;
std::cout<<(1 >> negzero)<<std::endl;
Run Code Online (Sandbox Code Playgroud)
  • 代码会产生什么输出?
  • 标准定义了哪些行,哪些行依赖于实现,哪些行是未定义的行为?

101*_*010 3

根据我对标准的解释:

\n\n

\xc2\xa73.9.1/p3 基本类型 [basic.fundamental]中的 C++标准实际上将球扔到了 C 标准中:

\n\n
\n

有符号和无符号整数类型应满足 C 标准第 5.2.4.2.1 节中给出的约束。

\n
\n\n

现在,如果我们转到 ISO/IEC 9899:2011 第 5.2.4.2.1 节,它给出了对\xc2\xa76.2.6.2/p2 整数类型的前向引用(重点是我的):

\n\n
\n

如果符号位为零,则不会影响结果值。如果符号位为 1,则应通过以下方式之一修改该值:

\n\n
    \n
  • 符号位为 0 的相应值被取反(符号和大小);

  • \n
  • 符号位的值为 \xe2\x88\x92(2^M) (两个\xe2\x80\x99s 补码);

  • \n
  • 符号位的值为 \xe2\x88\x92(2^M \xe2\x88\x92 1) (ones\xe2\x80\x99 补码)。

  • \n
\n\n

其中哪一个适用是实现定义的,就像是符号位为 1 且所有值位为零的值(对于前两个),\n 还是符号位和所有值位为 1(对于 Ones\xe2\x80\x99补码),是一个陷阱表示或一个正常值。在符号和大小以及个位补数的情况下,如果此表示是正常值,则称为负零。

\n
\n\n

因此,负零的存在是由实现定义的。

\n\n

如果我们继续第 3 段:

\n\n
\n

如果实现支持负零,则只能通过以下方式生成它们:

\n\n
    \n
  • &、|、^、~、<< 和 >> 运算符以及产生此类值的操作数;

  • \n
  • +、-、*、/ 和 % 运算符,其中一个操作数为负零\n且结果为零;

  • \n
  • 基于上述情况的复合赋值运算符。

  • \n
\n\n

未指定这些情况实际上是否生成负零或正常零,以及存储在对象中时负零是否变为正常零。

\n
\n\n

因此,您显示的相关案例是否会生成负零尚未明确。

\n\n

现在继续第 4 段:

\n\n
\n

如果实现不支持负零,则带有会产生此类值的操作数的 &、|、^、~、<< 和 >> 运算符的行为是未定义的。

\n
\n\n

因此,相关操作是否会导致未定义的行为,取决于实现是否支持负零。

\n