C中整数的无符号和后缀

Unsigned and suffix for integer in C

下面的代码没问题,编译器不会产生任何警告。但是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;
      |                         ^~~~~~~~~~~~~~~~~~~~

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

The type of an integer constant is the first of the corresponding list in which its value can be represented.

int
long int
long long int

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

  1. how can int store unsigned int?

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

  1. The following code produces warning, but why?

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

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

how can int store 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]

缺少 u 的十进制整数常量 18446744073709551615 有符号 。该值超出 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]