C 迭代到一个非常大的数字 - 关于 unsigned int 的编译器警告
C iteration up to a very large number - compiler warning about unsigned int
我有以下代码:
#include <stdio.h>
#define POWER 10000000000000000000
int main()
{
int i;
for (i = 0; i < POWER; i++)
{
....
}
return 0;
}
并且 gcc 编译器给我以下警告:
ex1.c:33:19: warning: integer constant is so large that it is unsigned [enabled by default]
ex1.c:33:2: warning: this decimal constant is unsigned only in ISO C90 [enabled by default]
如何使用 i
运行 遍历所有值直到达到 POWER
?我尝试将 i
声明为 unsigned int
但警告仍然存在。
值10000000000000000000
(= 10^19 如果我算对了)需要分配 64 位,这是 8 个字节。您收到警告是因为类型 int
使用 4 个字节,因此它无法存储该数字。使用 unsigned int
可以将最大正数加倍,但它是 4,294,967,295,这仍然不够。如果你想使用 int
你可以使用迭代循环。
for(i=0;i<p;i++){
for(j=0;j<p;j++){
for(k=0<p;k++){
/*loop*/
}
}
}
其中 p 将是 int
或 unsigned int
,其值为 POWER 的立方根(在这种情况下,立方根无效,因为 19%3 != 0 并且 p 将不是 int
,它更像是一个想法而不是实际解决方案)
您的常数 10000000000000000000
需要 64 位来表示它。在十六进制中,它是 0x8ac7230489e80000
。它可以用 unsigned 64 位类型表示,但不能用 signed 64 位类型表示。
从 C99 开始,所有整数常量都是某种有符号类型:int
、long int
或 long long int
中第一个值适合的类型。
C90(还没有 long long int
)有不同的规则。在 C90 中,无后缀的十进制整数常量的类型为 int
、long int
或 unsigned long int
.
gcc 的默认模式是-std=gnu90
,它支持C90 标准和GNU 特定的扩展。如果您使用的是 64 位系统,则 long
和 unsigned long
是 64 位。根据 C90 规则,您的常量是 unsigned long
类型(假设 unsigned long
至少是 64 位)。在 C99 及更高版本的规则下,假设没有比 64 位宽的整数类型,这就是约束违规。 (gcc 版本 5 将默认值更改为 -std=gnu11
。)
显然在 C90 规则下运行的编译器警告您 10000000000000000000
的含义因编译器在哪个版本的标准下运行而有所不同。
您可以通过以下更改使您的程序 "work":
#define POWER 10000000000000000000ULL // suffix to specify the type
...
for (unsigned long long = 0; i < POWER; i ++)
...
但是,尽管这使程序有效,但并不实用。以每纳秒一次迭代的速度,完成该循环将需要 3 个多世纪。我自己相当现代的计算机在大约 1.6 纳秒内执行一次 empty for
循环。无论您要解决什么问题,我都建议您要么找到一种不同的方法来解决它,要么将它简化为一个更小的问题。执行该循环的最快方法是等待几十年硬件变得更快,然后然后编译并执行它。
(这假设循环体是重要的。如果循环体什么都不做,编译器可能会完全优化循环。)
我有以下代码:
#include <stdio.h>
#define POWER 10000000000000000000
int main()
{
int i;
for (i = 0; i < POWER; i++)
{
....
}
return 0;
}
并且 gcc 编译器给我以下警告:
ex1.c:33:19: warning: integer constant is so large that it is unsigned [enabled by default] ex1.c:33:2: warning: this decimal constant is unsigned only in ISO C90 [enabled by default]
如何使用 i
运行 遍历所有值直到达到 POWER
?我尝试将 i
声明为 unsigned int
但警告仍然存在。
值10000000000000000000
(= 10^19 如果我算对了)需要分配 64 位,这是 8 个字节。您收到警告是因为类型 int
使用 4 个字节,因此它无法存储该数字。使用 unsigned int
可以将最大正数加倍,但它是 4,294,967,295,这仍然不够。如果你想使用 int
你可以使用迭代循环。
for(i=0;i<p;i++){
for(j=0;j<p;j++){
for(k=0<p;k++){
/*loop*/
}
}
}
其中 p 将是 int
或 unsigned int
,其值为 POWER 的立方根(在这种情况下,立方根无效,因为 19%3 != 0 并且 p 将不是 int
,它更像是一个想法而不是实际解决方案)
您的常数 10000000000000000000
需要 64 位来表示它。在十六进制中,它是 0x8ac7230489e80000
。它可以用 unsigned 64 位类型表示,但不能用 signed 64 位类型表示。
从 C99 开始,所有整数常量都是某种有符号类型:int
、long int
或 long long int
中第一个值适合的类型。
C90(还没有 long long int
)有不同的规则。在 C90 中,无后缀的十进制整数常量的类型为 int
、long int
或 unsigned long int
.
gcc 的默认模式是-std=gnu90
,它支持C90 标准和GNU 特定的扩展。如果您使用的是 64 位系统,则 long
和 unsigned long
是 64 位。根据 C90 规则,您的常量是 unsigned long
类型(假设 unsigned long
至少是 64 位)。在 C99 及更高版本的规则下,假设没有比 64 位宽的整数类型,这就是约束违规。 (gcc 版本 5 将默认值更改为 -std=gnu11
。)
显然在 C90 规则下运行的编译器警告您 10000000000000000000
的含义因编译器在哪个版本的标准下运行而有所不同。
您可以通过以下更改使您的程序 "work":
#define POWER 10000000000000000000ULL // suffix to specify the type
...
for (unsigned long long = 0; i < POWER; i ++)
...
但是,尽管这使程序有效,但并不实用。以每纳秒一次迭代的速度,完成该循环将需要 3 个多世纪。我自己相当现代的计算机在大约 1.6 纳秒内执行一次 empty for
循环。无论您要解决什么问题,我都建议您要么找到一种不同的方法来解决它,要么将它简化为一个更小的问题。执行该循环的最快方法是等待几十年硬件变得更快,然后然后编译并执行它。
(这假设循环体是重要的。如果循环体什么都不做,编译器可能会完全优化循环。)