【问题标题】:Unsigned and suffix for integer in CC中整数的无符号和后缀
【发布时间】:2021-02-28 08:15:58
【问题描述】:

以下代码是可以的,编译器不会产生任何警告。但是int怎么能存储unsigned int呢?

int c = UINT_MAX;
int d = 4294967295;
long int h = ULONG_MAX;

以下代码会产生警告,但为什么呢?这些基本上是上面long int h变量定义的扩展版本:

long int i = 18446744073709551615;
unsigned long int j = 18446744073709551615;

这是警告信息:

88308218/source.c:14:18: warning: integer constant is so large that it is 
     unsigned long int i = 18446744073709551615;
88308218/source.c:15:27: warning: integer constant is so large that it is 
     unsigned unsigned long int j = 18446744073709551615;

下面的代码是可以的。与上面int d的定义类似,只是后缀为u。似乎类型说明符比整数后缀弱。同样的问题也出现了关于在没有unsigned 类型的变量中存储的unsigned 值。

long int k = 18446744073709551615u;

示例源码如下:

#include <stdio.h>
#include <limits.h>

int main(void)
{
  // how can unsigned val be stored in normal int without prop type (unsigned int)
  // nor with suffix (u/U)
  int c = UINT_MAX;
  int d = 4294967295; // ok, same question with c
  long int h = ULONG_MAX; // ok, same question with c
  // the following produces warning, why? this is basically just expanded ver of h
  long int i = 18446744073709551615;
  long int j = 18446744073709551615u;
  unsigned long int k = 18446744073709551615;

  printf("%u\n", c);
  printf("%u\n", d);
  printf("%lu\n", h);
  printf("%lu\n", i);
  printf("%lu\n", j);
  printf("%lu\n", k);

  return 0;
}

编译结果:

$ gcc source.c
source.c: In function 'main':
source.c:12:16: warning: integer constant is so large that it is unsigned
   12 |   long int i = 18446744073709551615;
      |                ^~~~~~~~~~~~~~~~~~~~
source.c:14:25: warning: integer constant is so large that it is unsigned
   14 |   unsigned long int k = 18446744073709551615;
      |                         ^~~~~~~~~~~~~~~~~~~~

【问题讨论】:

  • 因为您似乎已经查找了对应于例如的define UINT_MAX,将其与您在此处的内容进行完全比较。差异与警告有很大关系。
  • 始终启用和构建额外的警告。我通常使用-Wall -Wextra -Wpedantic 构建。其中一个包括警告选项-Woverflow,它会给你一个int d = 4294967295;的警告
  • 1844 的“常量太大”警告的原因是该数字太大而无法适应编译器可用的任何有符号整数类型。另一方面,数字 4294... 确实 适合整数类型,特别是 64 位整数。所以编译器只是简单地通知你它会将 1844... 视为一个无符号数字,即使你没有告诉它(通过使用 u 后缀)。
  • 至于将UINT_MAX 分配给int 类型:这将导致整数溢出,这是未定义的行为。换句话说,不要那样做。至于将 4294... 分配给 int 类型:这可能没问题,如果 int 恰好是 64 位或更大。否则,这是未定义的行为。

标签: c variable-assignment


【解决方案1】:

int如何存储unsigned int

int 只存储ints。

在分配之前,转换为int。当int 范围之外的整数类型值转换为int 时,如int c = UINT_MAX;,该值将以实现指定的方式转换为int。避免使用这样的代码 - 它不可移植。


不行

以下代码产生 3 个警告。启用更多警告,如 -pedantic -Wall -Wextra -Wconversion 或寻求更好的编译器。这些警告很好地显示了转换的实现指定值。

int c = UINT_MAX;
// warning: signed conversion from 'unsigned int' to 'int' changes value from '4294967295' to '-1' [-Wsign-conversion]

int d = 4294967295;
// warning: overflow in conversion from 'long int' to 'int' changes value from '4294967295' to '-1' [-Woverflow]

long int h = ULONG_MAX;
// warning: signed conversion from 'long unsigned int' to 'long int' changes value from '18446744073709551615' to '-1' [-Wsign-conversion]

十进制整数常量18446744073709551615,缺少u有符号的。此值超出 long long 范围 - 因此发出警告。

long int i = 18446744073709551615;
// warning: integer constant is so large that it is unsigned

unsigned long int j = 18446744073709551615;
// warning: integer constant is so large that it is unsigned

改用18446744073709551615u,因为它在unsigned long long 范围内。

long int i = 18446744073709551615u; 仍将作为下一步的一部分发出警告:转换。现在好的unsigned long long 常量超出了long long 范围。

long int i = 18446744073709551615u;
// warning: signed conversion from 'long unsigned int' to 'long int' changes value from '18446744073709551615' to '-1' [-Wsign-conversion]

unsigned long int j = 18446744073709551615u;
// OK

不行

以下警告出于与上述类似的原因。

long int k = 18446744073709551615u;
// warning: signed conversion from 'long unsigned int' to 'long int' changes value from '18446744073709551615' to '-1' [-Wsign-conversion]

【讨论】:

    【解决方案2】:

    来自 C11 标准 (ISO/IEC 9899:2011) http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf ,(6.4.4.1,第 55-56 页)

    整数常量的类型是对应列表的第一个 在其中可以表示它的价值。

    int
    long int
    long long int
    

    因此,默认情况下,十进制整数常量是有符号整数。我们需要为其他类型提供后缀(根据 C11 文档)。

    1. int 如何存储 unsigned int?

    它无法存储。正如某些人在 cmets 中指出的那样,您需要使用 -Wall -Wextra -Wpedantic 选项启用额外的警告。

    1. 以下代码会产生警告,但为什么?

       long int i = 18446744073709551615;
       unsigned long int j = 18446744073709551615;
      

    原因:根据 C11 标准,j 仍然是 signed long integer,因为您没有添加后缀 ul。这就是编译器向unsigned long integer 抛出这样一个警告的原因。而long integer i 无法存储该值。

    【讨论】:

    • 请参阅 C11 文档中的引用。我提供了链接。请看。
    • 使用术语Integer constant,而不是decimal Integer constant
    • 感谢您的指点。我指的是 C11 而不是 C99。
    • 通过哔哔声来评论清理器。
    猜你喜欢
    • 2015-01-24
    • 2013-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多