我用C语言编写了一个数字符号计算器。我需要知道文件的最小大小(以字节为单位),这会导致签名为负数
程序以char形式从文件中读取字节,然后将其存储为整数,并不断增加对整数的使用,直到达到EOF。该程序工作正常。
FILE *fp;
char inpfile[20];
char c;
int sumdigsig = 0;
// reading in the name of the file using inpfile
printf("Please Enter name of the File:\n");
scanf("%s",inpfile);
// checking if the file exisits
if((fp = fopen(inpfile,"r")) == NULL){
fprintf(stderr,"File does no Exsist\n");
exit(1);
}
// If the file exsists using fgetc to read in until endoffile is reached
// and casting char to int and suming it
c = fgetc(fp);
while(c != EOF){
sumdigsig += (int)c;
c = fgetc(fp);
}
printf("%d\n",sumdigsig);
}
该程序运行正常,它只是一个参考,因此您可以了解正在发生的事情。运行很大的文件会导致预期的负数,但是我需要知道什么文件大小(以位为单位)将导致整数溢出并为负数。
答案 0 :(得分:2)
我需要知道什么文件大小(以位为单位)会导致整数溢出并为负数。
(您是说“文件大小为字节”吗?文件很少以位为单位。)
您的操作方式取决于文件中的字节。一旦您相加的字节总和超过INT_MAX
(请参阅limits.h
),int
累积总和的值将换为负值。
因此,特定文件的最大字节数 将比导致总和超过INT_MAX
的字节数少一。也就是说,比您在总和首次超过INT_MAX
时从文件中读取的字节数少一个字节;或者,从在代码中检测到这一点的实际意义上讲,它首先变为负数。
而且,正如评论之一指出的那样,如果所有字节都是0x00
,那么即使是无限大的文件也永远不会满足此条件。
编辑1:关于未定义溢出行为的注释,不是检测总和是否为负,而是测试(INT_MAX - sum)
是否小于最新值。读取字节的值,之前,将该字节的值添加到总和中。
编辑2:用代码表示:
我将其重写的核心循环
c = 0;
bytes = 0;
while (1) {
if ((c = fgetc(fp)) == EOF) break;
if ((INT_MAX - sumdigsig) >= c) {
sumdigsig += c;
bytes++;
} else {
break;
}
}
示例运行
head -c 1073741824 < /dev/urandom > large-file-of-random-bytes
./sum-file-bytes
Please Enter name of the File : large-file-of-random-bytes
sum is : 2147483572; read 16845621 bytes to reach that sum
head -c 1073741824 < /dev/zero > large-file-of-zeros
./sum-file-bytes
Please Enter name of the File : large-file-of-zeros
sum is : 0; read 1073741824 bytes to reach that sum
答案 1 :(得分:0)
在64位和32位计算机上,有符号整数值范围均为-2,147,483,648 to 2,147,483,647
因此,如果“ {sumdigsig
”超过“(正)最大值”,则它将回到负数范围。
让我们考虑一个小例子: 考虑范围是-10到+9
---> -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 ----
| |
--- +9 +8 +7 +6 +5 +4 +3 +2 +1 0 <---
考虑a = 4。 因此,如果您执行a = a + 6,即由于超出了范围,它将变为-10。
以相同的方式处理整数,如果该值超过最大值,则它将返回到负数范围。
证明:
#include <stdio.h>
int main()
{
// a contains the maxium value
int a = 2,147,483,647;
a = a + 1;
printf("%d", a);
return 0;
}
输出
-2,147,483,648
建议:与其使用signed-integer
,不如使用unsigned Integer
。您可以得到更大的射程,即2,147,483,647 + 2,147,483,648