【问题标题】:Warning: this decimal constant is unsigned only in ISO C90警告:这个十进制常量仅在 ISO C90 中是无符号的
【发布时间】:2012-04-14 00:53:59
【问题描述】:

一段代码:

long rangeVar = 0;
rangeVar = atol(p_value);

if (rangeVar >= -2147483648 && rangeVar <= 2147483647)

在编译时我得到:

警告:这个十进制常量仅在 ISO C90 中是无符号的

提前致谢

【问题讨论】:

标签: c compiler-construction long-integer iso c89


【解决方案1】:

是的,这是编译器不能很好地处理的一件事。问题是在编译过程中,这是被否定的数字 2147483648,而 2147483648 超出了整数的范围。即使 -2147483648 也不会!

无论如何,要摆脱警告,您可以通过编写 -2147483648LL 将常量转换为 64 位数字。
不过这太过分了,所以首选的方法是使用 INT_MIN 作为常量。但是你需要包含&lt;limits.h&gt;

【讨论】:

  • 不完全正确/准确。 C89 说:The type of an integer constant is the first of the corresponding list in which its value can be represented. Unsuffixed decimal: int, long int, unsigned long int; unsuffixed octal or hexadecimal: ...。因此,对于在某种兼容模式下工作的旧编译器或现代编译器 2147483648 将失败,如果它不能适应 unsigned long,而不是普通的 int。 C99 使用 long long intunsigned long long int 扩展了该列表,并且在 C99 模式下,后缀 (U)LL 是不必要的。当然,编译器错误也并非闻所未闻。
  • 那你会如何解释这个警告呢?我测试了,我得到了与 gcc 4.3.2 的 OP 相同的警告,当我使用 LL 后缀时没有警告。
  • 表示gcc默认不是C99模式。如果添加-std=c99,则会产生不同的警告:“由于数据类型范围有限,比较总是正确的”。惊喜。我什至不确定它默认处于什么模式以及为什么。
  • This 表示默认为gnu89,即GNU dialect of ISO C90 (including some C99 features). This is the default for C code.
  • @user1227514 很好,但你也读过 cmets 吗?如果-std=c99 有效(而不是更改源),您是否也尝试过?
【解决方案2】:

是的,2147483648 不是一个有效的正值,因为它超出了 32 位机器上 2 的补码的范围,所以他们只是想警告您,在某些编译器上,如果他们不这样做,这可能不会给您想要的值不要以现代方式处理否定。

我觉得值得添加另一个答案来指出,如果您查看大多数limits.h 实现,您会发现它们使用(-2147483647 - 1) 解决了这个问题。

【讨论】:

    【解决方案3】:

    十进制整数常量类型的规则在 1990 年和 1999 年版本的 ISO C 标准之间发生了变化。

    在 1990 版本中,无后缀十进制整数常量的类型是 intlong intunsigned long int 中可以表示其值的第一个类型。 (C90 没有long longunsigned long long 类型)。

    在1999和2011版本中,其类型为intlong intlong long int之一;它绝不是任何无符号类型。

    特定常量(例如2147483648)的类型将根据您使用的编译器的整数类型范围而有所不同。如果您的编译器的 long 类型恰好是 32 位,那么如果您的编译器使用 C90 规则,那么 2147483648 将是 unsigned long 类型,或者如果它使用 C11 规则(long long 保证是至少 64 位)。编译器会就此向您发出警告。

    您可以添加后缀来指定常量的类型——但没有用于普通签名int 的后缀。您可以为unsigned int 添加U,为long 添加L,为无符号长添加UL,等等。

    重要的是要记住-2147483648 不是一个整数常量;而2147483648 本身是一个整数常量,-2147483648 是一个将一元减号运算符应用于该常量的表达式。在 C90 规则下,如果常量是 unsigned long 类型,那是一个 unsigned 一元减号,根据无符号算术规则,它会产生值 2147483648。在 C99 或 C11 规则下,2147483648 可能是(签名的)long long 类型,否定它会产生 -2147483648,也是 long long 类型。

    您有时会看到使用(-2147483647 - 1) 来避免此问题的代码;给定 32 位 int2147483647 的类型为 int,表达式的结果产生预期的 int 值而不会溢出。

    当然,如果您的编译器对整数类型有不同的大小,这可能会变得更加复杂。

    更新:当我写这篇文章时,gcc 的默认方言是-std=gnu89。从那时起,它已更改为-std=gnu11(或未发布版本中的-std=gnu17)。我不确定这对警告有何影响。

    【讨论】:

    • 感谢您出色而清晰的回答。为了完整起见,可能值得添加关于实现定义的扩展整数类型的 C 标准 1999 版。如果没有一种类型是足够的,那么常量可以具有像 final 类型这样的扩展类型。例如,在 GCC(版本 4.4.7)中,常量 9223372036854775808(即 2^63)被“提升”为 16 字节数据类型 __int128_t(尽管它不是“真正的”EIT)。另请注意,这些规则对于八进制和十六进制表示形式略有不同,但我猜 OP 只对十进制表示感兴趣。
    • U 后缀表示无符号但不一定是unsigned int,例如如果一个只有U 的十进制常量对于unsigned int 来说太大了,那么它将具有unsigned long 类型。同样,如果值不适合 longL 将“升级”到 long long
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-11
    • 2012-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多