2

如何检测intC中的符号?

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


简单的符号位测试是与0.

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

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


第一种候选方法:模板测试。
由于 C 定义int无论整数编码如何,都必须具有符号位,因此以下内容应该有效。

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

问题变成了如何确定SignBitMaskC 中的值?
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;
}
4

3 回答 3

2

要找到负 0,只需检查设置了任何位的零。

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

或者回答标题中的问题:

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

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

于 2013-11-18T20:42:26.917 回答
1

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

编辑:你可能会作弊:

int sign(int x)
{
    if (x > 0) return 1;
    if (x > -1) return 0;
    return -1;
}
于 2013-11-18T20:29:34.807 回答
1

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

if (1 & -1) {
    if (3 & -1 == 1)
        printf("sign magnitude\n");
    else
        printf("twos complement\n");
} else
    printf("ones complement\n");
于 2013-11-09T00:26:23.240 回答