用C语言模拟Linux xxd命令:最后一行空格格式问题求助
解决C语言模拟xxd命令的最后一行空格格式问题
我已基本完成用C语言模拟Linux xxd命令的开发,但始终无法正确设置最后一行的空格格式。目前已处理了十六进制数字的空格,但无法计算出所需的其他空格。
原实现代码
#include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> const int MAX_CHAR = 16; int main(int argc, char *argv[]) { //command line argument for filename char *fileName = argv[1]; //open file and check for validity FILE *file = fopen(fileName, "r"); if (file == NULL) { printf("The file was not opened correctly\n"); return -1; } char line[MAX_CHAR]; //array to store characters int lineCount = 0; //counter for hexadecimal line display int charCount = 0; //counter for spacing of hex ascii values int breakIndex = MAX_CHAR; //integer to save what index the array is stopped at EOF //cycle through every 16 characters while(!feof(file)) { //read 16 characters for(int i = 0; i<breakIndex ; i++) { line[i]=fgetc(file); if (feof(file)) { breakIndex = i; line[i]='\0'; break; } } //print line count in hexadecimal printf("%.08x: ",lineCount); //print hexadecimal for each character for(int i = 0; i<breakIndex; i++) { printf("%.02x",line[i]); charCount++; if(charCount % 2 == 0) { printf(" "); } } //spaces for formatting output if(breakIndex == MAX_CHAR) { printf(" "); } else { int spaces = (MAX_CHAR - breakIndex) * 2 ; //printf("----%d-----",spaces); for(int i = 0 ; i< spaces ; i++) { printf(" "); } } //print actual characters for(int i = 0; i<breakIndex ; i++) { if(!isprint(line[i])) { line[i]= '.'; } } line[16] = '\0'; printf("%s",line); printf("\n"); //increment line count lineCount+=16; } //close file fclose(file); return 0; }
问题分析
原代码的空格计算逻辑存在两个核心问题:
- 未重置
charCount:每次处理新行时,charCount保留上一行的计数,导致后续行的组空格逻辑完全混乱。 - 空格计算不完整:仅考虑了少输出的十六进制位数,忽略了xxd格式中每个字节间的空格、前8字节与后8字节的分隔空格,以及满行末尾的对齐空格。
标准xxd的格式规则:
- 每行16字节,每个字节输出两位十六进制,字节间加空格;
- 前8字节结束后额外加一个空格分隔前后段;
- 十六进制部分结束后加一个空格,再输出字符部分。
修正后的代码
#include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> const int MAX_CHAR = 16; int main(int argc, char *argv[]) { if (argc < 2) { printf("Usage: %s <filename>\n", argv[0]); return -1; } char *fileName = argv[1]; FILE *file = fopen(fileName, "rb"); // 二进制模式打开,避免换行符转换 if (file == NULL) { printf("The file was not opened correctly\n"); return -1; } unsigned char line[MAX_CHAR]; // 用unsigned char避免符号扩展问题 int lineCount = 0; int bytesRead; while ((bytesRead = fread(line, 1, MAX_CHAR, file)) > 0) { // 输出行地址 printf("%.08x: ", lineCount); // 输出十六进制部分 for (int i = 0; i < bytesRead; i++) { printf("%.02x", line[i]); // 字节间加空格,最后一个字节除外 if (i != bytesRead - 1) { printf(" "); } // 前8字节结束后加额外分隔空格 if (i == 7 && bytesRead > 8) { printf(" "); } } // 计算需要补充的空格数,对齐到满行格式 int printedLength = 0; if (bytesRead <= 8) { printedLength = bytesRead * 3; // 每个字节占3字符:xx + 空格 } else { // 前8字节长度 + 分隔空格 + 剩余字节长度 printedLength = 8*3 + 2 + (bytesRead - 8)*3; } // 满行时冒号后到字符前的总长度为50,计算差值补空格 int spacesNeeded = 50 - printedLength; for (int i = 0; i < spacesNeeded; i++) { printf(" "); } // 输出字符部分 for (int i = 0; i < bytesRead; i++) { printf("%c", isprint(line[i]) ? line[i] : '.'); } printf("\n"); lineCount += bytesRead; } fclose(file); return 0; }
关键修正点
- 二进制模式打开文件:避免Windows环境下换行符被自动转换,保证读取字节的准确性。
- 使用
unsigned char存储字节:防止带符号字节的符号扩展导致十六进制输出错误。 - 重构空格输出逻辑:按行内字节数直接控制空格,去掉全局计数,避免累积错误。
- 准确计算对齐空格:根据已输出的十六进制内容长度,补空格到满行的标准格式长度,确保最后一行与其他行对齐。
- 修复行地址递增:按实际读取的字节数递增行地址,适配文件大小不是16倍数的场景。
内容的提问来源于stack exchange,提问作者s k y l i n e
相关产品推荐
相关产品推荐

