fgetc是C语言的标准函数。如果不做深究,从函数名就很自然的认为就是get一个char,因此就产生了如下代码,函数的作用是读取文本文件中的一行:
注:该段代码中的 LINE_LENGTH 是自定义的宏,可以在自己的头文件中定义
#define LINE_LENGTH 1024
int fgetline(FILE* file_p, char* line_string){
char ch='\0';
int i=0;
if(file_p==NULL){
return -1;
}
reset_string(line_string);
do{
ch=fgetc(file_p);
if(ch!=EOF&&ch!='\n'){
*(line_string+i)=ch;
i++;
}
}while(ch!=EOF&&ch!='\n'&&i!=LINE_LENGTH);
if(i==LINE_LENGTH){
return -127;
}
*(line_string+i)='\0';
if(ch==EOF&&i==0){
return 1;
}
else{
return 0;
}
}
基于上述函数,做一个简单的main,如下:
#include <stdio.h>
#define LINE_LENGTH 1024
int main(int argc, char** argv){
char line_buffer[LINE_LENGTH]="";
int i;
FILE* file_p=fopen("my_test.txt","r");
if(file_p==NULL){
return 1;
}
while(!feof(file_p)){
fgetline(file_p,line_buffer);
printf("%s\n",line_buffer);
for(i=0;i<LINE_LENGTH;i++){
*(line_buffer+i)='\0';
}
}
fclose(file_p);
return 0;
}
然而,上述代码却有内在问题。实测在 x86 平台上的各个 OS 都未发现异常。但是当移植到 ARM64 架构的 Linux 系统时,却出现了问题。明明已经读到了文件末尾,但是 fgetline 中的循环却还在进行。这就导致了 segmentation fault。
实际上,fgetc 返回的是一个 int 类型,可正可负。如果是-1,则说明读取失败或读到了 EOF。然而如果系统环境和编译器默认 char 类型时 unsigned char,那么问题就来了。
unsigned char 的范围是0~255,此时,如果fgetc 返回了-1,上面代码示例中的fgetline中的循环并不会跳出,因为 ch 的取值到不了-1,而只能是255,判断循环跳出的语句不能触发。
正确的代码如下:
int fgetline(FILE* file_p, char* line_string){
int ch='\0'; //使用 int 类型
int i=0;
if(file_p==NULL){
return -1;
}
reset_string(line_string);
do{
ch=fgetc(file_p);
if(ch!=EOF&&ch!='\n'){
*(line_string+i)=ch;
i++;
}
}while(ch!=EOF&&ch!='\n'&&i!=LINE_LENGTH);
if(i==LINE_LENGTH){
return -127;
}
*(line_string+i)='\0';
if(ch==EOF&&i==0){
return 1;
}
else{
return 0;
}
}
数据类型还是要经常学习。