1:知识点总结
Unix每行结尾为"\n",
Windows系统每行结尾是"\r\n"
printf输出时,如果内部字段含有\r,会自动跳转到行首进行后续的输出。
printf输出时,有时候一直不打印,是因为printf底层是有缓冲区的,要在终端输出要用换行。
2:简单问题描述。
行为:我在做一个读取配置文件并进行解析的简单demo,按行读取,使用=进行分割,对value值进行拼接。
问题:按行读取后,printf打印一直无法理解,出现现象一直如下:
例如: const char* test="mytest of data.\r"; printf("test:[%s][%lu] \n", test, strlen(test)); 实际输出为: ][16] mytest of data.
因为一直没想到行尾描述符的差异,以及printf输出该现象第一次遇到,定位稍久。
3:问题定位。
通过猜测,加日志的的方式进行定位。
最后发现,按行读取文件,=解析后,读取到的字符串比原文件中除了\n还多了一个字符。
想到windows环境下,行尾标志"\r\n"的差异。
4:按行读配置文件,查找key值,=进行解析,并拼接的测试demo
#include <stdio.h> #include <stdlib.h> #include <string.h> /******************************* 1:读配置文件 2:解析配置文件中的所有行,解析出需要的字段 3:对解析出的字段进行拼接打印 ********************************/ typedef struct _t_project_ctrol { char target_name[40]; char major_version[5]; char sub_version[5]; char stage_version[5]; }PROJECT_CTROL; enum PROJECT_CTROL_ENUM { PROJECT_NAME, PROJECT_MAJOR_VERSION, PROJECT_SUB_VERSION, PROJECT_STAGE_VERSION, PROJECT_OTHER_ERROR }; enum PROJECT_CTROL_ENUM parse_para(const char* data) { const char* project_name = "test_project_name"; const char* major_version = "test_major_version"; const char* sub_version = "test_sub_version"; const char* stage_version = "test_stage_version"; if(strstr(data, project_name) != NULL) { return PROJECT_NAME; } if(strstr(data, major_version) != NULL) { return PROJECT_MAJOR_VERSION; } if(strstr(data, sub_version) != NULL) { return PROJECT_SUB_VERSION; } if(strstr(data, stage_version) != NULL) { return PROJECT_STAGE_VERSION; } return PROJECT_OTHER_ERROR; } int parse_line(const char* data, PROJECT_CTROL* result_t) { if(data == NULL ||data[0] == '\0') { return -1; } //使用=进行切割 // 实际结果是 data: len:20 ject_name=hxxllo // 期望结果是 data:wucg_project_name=hxxllo len:20 // printf("data:%s len:%lu \n", data,strlen(data)); //因为fgets函数读windows配置文件,行尾是\r\n char * spilt_char; spilt_char = strchr(data, '='); if(spilt_char == NULL) { return -1; } spilt_char++; switch(parse_para(data)) { case PROJECT_NAME: memcpy(result_t->target_name, spilt_char, strlen(spilt_char)); break; case PROJECT_MAJOR_VERSION: memcpy(result_t->major_version, spilt_char, strlen(spilt_char)); break; case PROJECT_SUB_VERSION: memcpy(result_t->sub_version, spilt_char, strlen(spilt_char)); break; case PROJECT_STAGE_VERSION: memcpy(result_t->stage_version, spilt_char, strlen(spilt_char)); break; default: break; } return 0; } int get_config_information(char* proj_version) { FILE *fp; const char * filename="hello_config.mk"; char line[1000]={0}; fp = fopen(filename, "r"); if(fp==NULL) { printf("fopen file error \n"); return -1; } PROJECT_CTROL project_verinson_t; memset(&project_verinson_t, 0, sizeof(PROJECT_CTROL)); int line_len = 0; while(!feof(fp)) { memset(line, 0, 1000); fgets(line,1000,fp); //会影响到printf函数的打印 因为windows和linux换行符导致 line_len = strlen(line); //这里因为行尾终结符号为\r\n line[line_len-2] = '\0'; parse_line(line, &project_verinson_t); } fclose(fp); sprintf(proj_version, "%s-%s.%s.%s", project_verinson_t.target_name, project_verinson_t.major_version, project_verinson_t.sub_version, project_verinson_t.stage_version); return 0; } int main() { char version [50]; memset(version, 0, 50); get_config_information(version); printf("get project version is [%s] \n", version); return 0; } /********************** 配置文件:hello_config.mk test_project_name=hxxllo test_major_version=1 test_sub_version=0 test_stage_version=1 输出结果: get project version is [hxxllo-1.0.1] **********************/