即使使用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个产品计算,每个都有自己的类型数学。

60123456intlong取决于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的适用细节..

常量60123456128的类型为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 * 12860123456 * 128ULL或两者。