Ubuntu下C程序编译警告:feof参数传递引发指针转换问题咨询
feof警告并修复你的文件逆序C程序 首先咱们先解决你遇到的那个警告,然后再梳理代码里其他影响功能的问题。
关于feof警告的原因
先看你拿到的警告内容:
reverseFileContent.c: In function ‘main’:
reverseFileContent.c:51:16: warning: passing argument 1 of ‘feof’ makes pointer from integer without a cast [-Wint-conversion]
while(!feof(inputFile))
这个警告的根源是你打开输入文件的代码写错了,导致inputFile根本不是一个合法的FILE*指针,而是变成了整数:
if( (inputFile = fopen(argv[1], O_RDONLY))) { fprintf(stderr, "Input file doesn't exist.\n"); exit(-1); }
这里有两个错误:
fopen的第二个参数需要是字符串模式(比如"r"表示只读),而O_RDONLY是系统调用open的参数(整数类型),传给fopen完全不兼容,会导致fopen调用失败返回NULL。- 判断逻辑搞反了:
if(inputFile = fopen(...))的意思是如果文件打开成功,你就报错退出,这完全和你想要的逻辑相反。
正确的写法应该是:如果fopen返回NULL(打开失败),才报错退出,同时用正确的模式字符串:
if( (inputFile = fopen(argv[1], "r")) == NULL) { fprintf(stderr, "Input file doesn't exist or cannot be opened.\n"); exit(-1); }
因为之前的错误,inputFile被赋值为NULL(在多数系统里是整数0),当你把它传给需要FILE*类型参数的feof时,编译器就会抛出类型不匹配的警告。
你的代码还有其他几个严重问题,必须一起修复
1. 输出文件打开的逻辑同样错误
这段代码的问题和输入文件一样,逻辑完全搞反,而且模式也不对:
if((outputFile = fopen(argv[2], "a+"))) { fclose(inputFile); exit(-1); }
- 你应该在
fopen失败(返回NULL)时才报错退出。 "a+"是追加模式,不会清空已有文件内容,如果你需要清空文件再写入,应该用"w"(只写,创建或截断文件)或者"w+"(读写)。
修正后:
if((outputFile = fopen(argv[2], "w")) == NULL) { fclose(inputFile); fprintf(stderr, "Cannot create or open output file.\n"); exit(-1); }
2. fseek获取文件大小的用法错误
你用fileSize = fseek(inputFile, 0, SEEK_END);是错的,fseek的返回值是状态码(成功返回0,失败返回-1),不会返回文件大小。要获取文件大小,得先fseek到末尾,再用ftell获取当前指针位置:
// 移动到文件末尾 if (fseek(inputFile, 0, SEEK_END) != 0) { fprintf(stderr, "Failed to seek to end of input file.\n"); fclose(inputFile); fclose(outputFile); exit(-1); } // 获取文件大小 long fileSize = ftell(inputFile);
3. 逆序逻辑完全错误
你现在的代码是在一个从fileSize-1到0的循环里,嵌套了一个while(!feof)循环,这会导致你把整个文件内容重复写fileSize次,完全不是逆序效果。而且用fgets按行读取也没法实现字节级的逆序。
要实现整个文件内容逆序输出(比如输入abc123输出321cba),正确的思路是:从文件末尾开始,每次读取BUFFER_SIZE字节的块,把这个块逆序后写入输出文件,直到处理到文件开头。
核心逻辑示例:
long currentPos = fileSize; while (currentPos > 0) { // 计算本次读取的字节数:剩余大小大于BUFFER_SIZE就读256字节,否则读剩余的 int readSize = (currentPos >= BUFFER_SIZE) ? BUFFER_SIZE : currentPos; // 移动指针到要读取的块的起始位置 if (fseek(inputFile, currentPos - readSize, SEEK_SET) != 0) { perror("fseek failed"); break; } // 读取块内容 int bytesRead = fread(buffer, 1, readSize, inputFile); if (bytesRead != readSize) { perror("fread failed"); break; } // 逆序写入这个块 for (int i = bytesRead - 1; i >= 0; i--) { fputc(buffer[i], outputFile); } // 更新当前位置 currentPos -= readSize; }
4. feof的误用(即使参数正确,写法也不对)
feof只有在已经尝试读取并失败后才会返回非零值,所以while(!feof(inputFile))的写法通常会导致最后一次读取重复执行。正确的写法应该把读取操作放在循环条件里,比如:
while (fgets(buffer, BUFFER_SIZE, inputFile) != NULL) { fputs(buffer, outputFile); }
不过在你的逆序需求里,这个循环完全不适用,直接删掉就行。
内容的提问来源于stack exchange,提问作者Chuchoo

