即使使用unsigned long int也会出现溢出
当我进行以下计算时:
unsigned long long int data_size = 60123456 * 128 * sizeof(double); printf("data_size= %llu \n", data_size);
我出乎意料地得到溢出警告:
test.c:20:49: warning: overflow in expression; result is -894132224 with type 'int' [-Winteger-overflow] unsigned long long int data_size = 60123456 * 128 * sizeof(double); ^ 1 warning generated.
即使我使用unsigned long long int
我也无法理解为什么会出现此错误! 有人可以解释原因吗? 谢谢
在将值赋给变量之前发生溢出。 为避免使用long long后缀:
60123456LL * 128 * sizeof(double)
(评论还提出ULL,这里没有必要,因为值在符号范围内,但这是通用的方法)
你转得太久了很长时间。 60123456 * 128
仍然是一个溢出的int表达式。
请尝试使用60123456LL * 128
。 (LL因为结果值不能保证适合长期。)
unsigned long long int data_size = 60123456 * 128 * sizeof(double); // trouble-some code
目标类型为unsigned long long int data_size =
与产品计算无关60123456 * 128 * sizeof(double)
。
最好确保使用至少目标类型的大小来完成数学运算以避免溢出。 在OP的情况下,这意味着LLU
的常数。
有2个产品计算,每个都有自己的类型数学。
60123456
是int
或long
取决于int
范围。 我们假设它是一个int
。
60123456 * 128
是一个int * int
。 数学乘积7695802368
超过32位有符号整数范围,因此带有32位int
带符号整数溢出或未定义行为(UB)。
如果60123456 * 128
没有溢出,说64位int
,则下一个乘法将是* sizeof(double);
因此int * size_t
会生成size_t
类型的产品。
产品计算应至少使用unsigned long long
数学,如下所示:
unsigned long long int data_size = 1LLU * 60123456 * 128 * sizeof(double); // or unsigned long long int data_size = 60123456LLU * 128 * sizeof(double); // or unsigned long long int data_size = 60123456; data_size *= 128 * sizeof(double); // or avoiding naked magic numbers #define A_HEIGHT 60123456 #define A_WIDTH 128 unsigned long long int data_size = 1LLU * A_HEIGHT * A_WIDTH * sizeof(double);
sizeof (double)
提示代码试图找到某些类似2D的结构的大小。 我希望代码如下。 请注意, sizeof
的结果类型是size_t
,因此产品数学至少使用size_t
math来完成。
size_t data_size = sizeof(double) * 60123456 * 128; printf("data_size= %zu\n", data_size);
另请参阅为什么在C中将1,000,000,000写入1000 * 1000 * 1000? 我的答案理由不使用1000 * 1000 * 1000的适用细节..
常量60123456
和128
的类型为int
,因此表达式60123456 * 128
也是int
类型。 该表达式的值将溢出int
的范围。 在这种情况下,编译器能够检测到它,因为两个操作数都是常量。
您应该在第一个操作数上使用ULL
后缀来生成常量unsigned long long
的类型。 这样它匹配分配的类型。 然后,对于涉及此值的任何操作,在应用操作之前,另一个操作数将被提升为unsigned long long
并且您将不会有任何溢出。
因此,结果表达式应如下所示:
unsigned long long int data_size = 60123456ULL * 128 * sizeof(double);
词法分析器在翻译阶段7(将预处理标记转换为C标记)中附加常量类型。参见ISO9899 5.1.1.2 Translation phases
。 正如其他人所说,词法分析器将在你的常量上附加int
类型而不是unsigned long long
,并且为了让default arithmetic conversions
在你需要的赋值的右侧生成unsigned long long
类型的常量要告诉词法分析器在生成溢出的操作*
至少一个常量上附加unsigned long long
类型,所以通过写入60123456ULL * 128
或60123456 * 128ULL
或两者。