C中的问题

时间:2012-10-03 04:02:08

标签: c unix

你可以说我对C比较陌生,但我需要澄清一个问题。 我有一个代表数字的char []。如果此char []长于LONG_MAX,我想告诉用户它太长了。问题是,当我将其值与浮点数进行比较时,它会被截断。这就是我的意思。

int main(int argc, char ** argv) {

  char str[] = argv[1]; /* I set it to 9223372036854775809, only +1 higher than LONG_MAX */ 
  double l = atof(str); 
  double j = LONG_MAX; 

  printf("%lf\n", l); /* This prints 9223372036854775808.000000, which is LONG_MAX ??? WHY?? */
  printf("%lf\n", j); /* This prints same as above, 9223372036854775808.000000 */ 

  printf("%s\n", l > j ? "true" : "false"); /* false */

  return 0; /* what am I doing wrong? */

}

更新:

我尝试了你的iret解决方案,但我仍遇到了同样的问题

 j = LONG_MAX; 
  int iret = sscanf (str, "%lf", &l);
  if (iret != 1)
    return 0; /* conversion was bad */
  else {
    if (l > j || l < -(j))
      return 0; /* too small or too large */
  }

  printf("%lf\n", l); 
  printf("%lf\n", j);

  printf("%s\n", l > j ? "true" : "false");

4 个答案:

答案 0 :(得分:1)

您可以使用strtol轻松检查溢出,但需要一些额外的工作。

const char *str = ...;
char *e;
long x;

errno = 0;
x = strtol(str, &e, 0);
if (!*str || *e) {
    fprintf(stderr, "invalid number: %s\n", str);
    exit(1);
}
if ((x == LONG_MAX || x == LONG_MIN) && errno == ERANGE) {
    fprintf(stderr, "number too large: %s\n", str);
    exit(1);
}

现在,我们来谈谈strtod(或atof的问题,这只是strtod的破解版本。)

如果您将9223372036854775809转换为double,则9223372036854775808 正确double具有53位精度,而64位long具有64位精度。一旦开始使用浮点数,就需要为舍入做好准备。

例如,以下代码中存在舍入错误。你能发现它吗?

double x = 0.1;

脚注:我假设这里有64位long和IEEE双精度double

答案 1 :(得分:0)

根据atof的“man”页面:

  

http://linux.die.net/man/3/atof

     

atof()函数转换指向的字符串的初始部分   由nptr加倍。 ... atof()不会检测错误。

这就是为什么我更喜欢使用“sscanf”:

int iret = sscanf (SOME_TEXT, "%lf", &SOME_DOUBLE);

如果“iret!= 1”,那么我知道发生了错误,可以采取相应的措施。

... IMHO

PS:

你为什么不宣布“l”和“j”。调皮顽皮!您应该始终声明您的变量,即使在FORTRAN和Basic中也是如此;)

为什么不将它们声明为float(“%f”)或double(“%lf”)?

答案 2 :(得分:0)

我相信你输入两个值的原因是“9223372036854775808.000000”是由于浮点近似的精度限制。

顺便说一下,该值不是LONG_MAX,而是LONG_MAX + 1 -> 2^63

根据定义,LONG_MAX的表示完全(作为整数)需要63位精度。但是,在像double这样的64位浮点表示中,只有53位精度,因为其他位需要存储符号和指数。这就是为什么LONG_MAXLONG_MAX + 2最终都被舍入到9223372036854775808 <=> 2^63

要正确处理这种情况,或许请查看strtol,当输入超出范围时,会设置错误代码。

答案 3 :(得分:0)

你的长期似乎是63位。浮点数有23个有效位(或24个有前导1)。你的长点在高24位中完全相同。所以他们变得一样。 浮点数基本上是尾数* 2 ^指数。指数确保幅度仍然匹配。但是你只有23位的尾数。所以它变成top23bitsoflong * 2 ^(numberofremainingbits)。 这有点简化,忽略了前导和指数偏差。