【问题标题】:How to uniformly detect an integer’s sign bit across various encodings (1's complement, 2's complement, sign magnitude)?如何在各种编码(1 的补码、2 的补码、符号幅度)中统一检测整数的符号位?
【发布时间】:2013-11-08 22:54:15
【问题描述】:

如何在 C 中检测 int 符号?

这个问题主要是关于历史机器的。我要问的是如何区分整数是0还是-0。在 1 的补码和符号/幅度 int 编码中,0(或 +0)和 -0 都是可能的。


简单的符号位测试是与0比较。

int x;
printf("sign bit is %s\n", (x < 0) ? "set" : "not set");

但是当x-0 时,这在 1 的补码和符号幅度上会失败。


第一种候选方法:模板测试。
由于 C 定义 int 必须有一个符号位,无论整数编码如何,以下应该可以工作。

int x;
int SignBitMask = tbd;
printf("sign bit is %s\n", (x & SignBitMask) ? "set" : "not set");

问题变成了如何在 C 中确定SignBitMask 的值?
SignBitMask = INT_MAX + 1 似乎是一个起点。


第二种候选方法:创建函数并检查位模式:

int IsSignBitSet(int x) {
  if (x > 0) return 0;
  if (x < 0) return 1;
  int zp = 0;
  if (memcmp(&x, &zp, sizeof x) == 0) return 0;
  int zn = -0;  // Is this even the way to form a -0?
  if (memcmp(&x, &zn, sizeof x) == 0) return 1;
  // If we get here, now what?
  return ?;
}

我认为没有便携式统一解决方案 - 可能是因为不再需要。

为什么:我想知道如何检测和打印各种带符号的零。

注意:我在这里故意避开了“C”标签,并认为我会先尝试“历史”标签。


[编辑]答案

结合3个答案的信息和C11dr 6.2.6.2“整数类型”(对于int,单个符号位必须存在,正符号位为0,负符号位为1 ),一个解决方案(看起来独立于 1 的补码、2 的补码和符号/幅度整数编码)是

int IsSignBitSet_Best(int x) {
  // return 1 if x is less than 0 _or_ x is arithmetically 0 with some bit set.
  return (x < 0) || ((x == 0) && (* ((unsigned int*) &x) ));
}

直接掩码方法最简单,但还没有提出高度可移植的掩码定义

int IsSignBitSet_Simple(int x) {
  static unsigned SignBitMask = 0x80;  // Or some other platform dependent mask
  return ((unsigned)x & SignBitMask) != 0;
}

【问题讨论】:

  • 如果您只包含像history 这样的次要标签(甚至可能需要被烧掉),问题可能不会被很多人看到。
  • C 中的“符号位”是所有这些表示的第一位 (MSB)。 -0 被视为负数。
  • @Eric Postpischil 我对您的补充编辑表示赞赏。

标签: c history twos-complement


【解决方案1】:

要找到负 0,只需检查所有设置的任何位是否为零。

int testForNegative0(int x) { 
   return (x==0 && *((unsigned int*)&x)); 
}

或者回答标题中的问题:

int hasSignBitSet(int x) { 
   return (x<0) || testForNegative0(x);
}

这适用于您提到的 3 种编码,它可能不适用于更深奥的编码。

【讨论】:

  • 非常直接的方法。如果您知道这种非 2 的补码整数编码处于活动状态时是否使用了 BITD(过去),请发表评论。
  • -0 == 0 在补码 C 中吗?
  • @ribond,根据wikipedia, yes
  • @rlbond 一个补码零(0 或 -0)的行为算术相同。所以-0 == 0 是真的。这与浮点数 -0.0 == 0.0 的计算结果为 true 非常相似。但我会研究 C 规范。
  • @rlbond C11dr 6.2.6.2 确实讨论了负 0。我还没有看到支持我的“-0 在算术上与 0 相同”的直接声明,但我认为这是隐含的。
【解决方案2】:

不知道你在问什么。如果您问“我们如何确定机器是补码、补码还是符号幅度?”你可以使用:

if (1 & -1) {
    if (3 & -1 == 1)
        printf("sign magnitude\n");
    else
        printf("twos complement\n");
} else
    printf("ones complement\n");

【讨论】:

  • 谢谢,但我要问的是如何区分整数是0还是-0。在 1 的补码和符号/大小int 编码中,0(或 +0)和 -0 都是可能的。现在大多数机器都是 2 的补码整数,不会出现 -0。
  • 我看到将@rlbond(在另一个答案中)建议的评论与这个答案结合起来会提供一个解决方案。
【解决方案3】:

您的问题有点令人困惑。你提前知道编码吗?如果不是,那么您要问的是不可能的,因为不同编码的映射不同。例如,字节1111111 在一个补码中的“符号”为 0,但在二进制补码中的符号为 -1。那么如何有一种通用的方法来检查它们是否定义不同呢?

编辑:你也许可以作弊:

int sign(int x)
{
    if (x > 0) return 1;
    if (x > -1) return 0;
    return -1;
}

【讨论】:

  • 有各种帖子展示了如何通过某种程度的可移植性(参见本文中的@Chris Dodd)确定整数编码是 2 的补码、1 的补码或符号大小。因此,如果事先不知道编码,则可以识别出来。
  • 如果这就是您要问的,那么您几乎已经有了答案。二进制补码只有一个零,所以很容易检查。一个补码的零是1111111100000000,符号幅度是1000000000000000,因此您可以使用检测这些特定数字的函数进行检查(当然,您必须调整到字长)
  • BTW "10000000,在一个补码中的 "符号" 为 0"。 一个补码 10000000 不是值 -127(因此是 1 的符号)吗?
  • 糟糕,我的意思是“11111111”。
  • 顺便说一句:感谢标签更新。我会说 1111111 的补码 (-0) 的符号为 1,算术值为 0。
猜你喜欢
  • 1970-01-01
  • 2016-05-18
  • 2015-07-04
  • 1970-01-01
  • 2014-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-23
相关资源
最近更新 更多