一个简单的 C 程序是否可以模仿默认的 'xxd' 命令,使其 diff 输出返回 0?

标签 c hex diff hexdump xxd

我正在尝试编写一个 C 可执行文件,它将产生与默认 xxd 命令相同的输出。例如,假设我有一个名为 test.txt 的相当小的文本文件和一个名为 myxxd

的可执行文件

因此,我首先使用以下方法进行比较:

$ touch correct-xxdoutput.txt test-output.txt
$ xxd test.txt > correct-xxdoutput.txt

然后将我的可执行文件用于相同的操作,但输出到不同的输出文件:

$ ./myxxd test.txt > test-output.txt
$ diff correct-xxdoutput.txt test-output.txt
$

我已经非常接近于一些猜测,但我的格式总是以某种方式出错,而且我并不真正理解 xxd 是如何生成 hexDumps 的。感觉我只是在这里采取了完全错误的方法,但也许以我目前的 C 知识水平,这项任务超出了我的潜力。

我的代码(另请参阅:https://pastebin.com/Vjkm8Wb4):

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define SIZE 256

//Prototypes
void hexDump(void*, int);

int main(int argc, char *argv[])
{
    //Create and open filestream
    FILE *myfile;
    myfile =fopen(argv[1],"rb");

    for ( ; ; )
    {
        unsigned char buffer[SIZE];
        size_t n = fread(buffer, 1, SIZE, myfile);

        if (n > 0)
            hexDump(buffer, n);
        if (n < SIZE)
            break;
    }

    fclose(myfile);
    return 0;
}


void hexDump (void *addr, int len)
{
    int i;
    unsigned char bufferLine[17];
    unsigned char *pc = (unsigned char*)addr;

    for (i = 0; i < len; i++)
    {
        if ((i % 16) == 0)
        {
            if (i != 0)
                printf (" %s\n", bufferLine);

            if (pc[i] == 0x00) exit(0);
            printf ("%08x: ", i);
        }

        // Prints Hexcdoes that represent each chars.
        printf ("%02x", pc[i]);
        if ((i % 2) == 1)
            printf (" ");

        if ((pc[i] < 0x20) || (pc[i] > 0x7e))
        {
            bufferLine[i % 16] = '.';
        }

        else
        {
           bufferLine[i % 16] = pc[i];
        }    

        bufferLine[(i % 16) + 1] = '\0'; //Clears the next array buffLine
    }

    while ((i % 16) != 0)
    {
        printf ("  ");
        i++;
    }

    printf ("     %s\n", bufferLine);
}

最佳答案

您的代码存在多个问题,包括:

  • 您没有检查是否有要打开的文件名。
  • 您没有检查是否打开了指定的文件。
  • 您没有处理输出偏移量的机制,因此第一个 block 之后行开头的地址是错误的。
  • 您的代码测试零字节并在遇到零字节时静默退出。这很糟糕——两次。一次是因为旨在处理二进制数据的程序必须处理零字节以及 1..255 中的值;一次是因为静默退出(并通过 exit(0) 启动成功)是不好的。您应该报告问题(关于标准错误,而不是标准输出)并以错误状态(非零状态)退出。

核心格式似乎基本没问题;填充文件末尾的短数据行也存在问题。

我想出了这段代码,它与你的代码非常相似(但重新格式化以至少适应我的一些风格偏见——但大多数时候我的风格与你的相差不远):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SIZE 256

void hexDump(size_t, void *, int);

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        fprintf(stderr, "Usage: %s file\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    FILE *myfile = fopen(argv[1], "rb");
    if (myfile == 0)
    {
        fprintf(stderr, "%s: failed to open file '%s' for reading\n", argv[0], argv[1]);
        exit(EXIT_FAILURE);
    }

    unsigned char buffer[SIZE];
    size_t n;
    size_t offset = 0;
    while ((n = fread(buffer, 1, SIZE, myfile)) > 0)
    {
        hexDump(offset, buffer, n);
        if (n < SIZE)
            break;
        offset += n;
    }

    fclose(myfile);
    return 0;
}

void hexDump(size_t offset, void *addr, int len)
{
    int i;
    unsigned char bufferLine[17];
    unsigned char *pc = (unsigned char *)addr;

    for (i = 0; i < len; i++)
    {
        if ((i % 16) == 0)
        {
            if (i != 0)
                printf(" %s\n", bufferLine);
            // Bogus test for zero bytes!
            //if (pc[i] == 0x00)
            //    exit(0);
            printf("%08zx: ", offset);
            offset += (i % 16 == 0) ? 16 : i % 16;
        }

        printf("%02x", pc[i]);
        if ((i % 2) == 1)
            printf(" ");

        if ((pc[i] < 0x20) || (pc[i] > 0x7e))
        {
            bufferLine[i % 16] = '.';
        }
        else
        {
            bufferLine[i % 16] = pc[i];
        }

        bufferLine[(i % 16) + 1] = '\0';
    }

    while ((i % 16) != 0)
    {
        printf("  ");
        if (i % 2 == 1)
            putchar(' ');
        i++;
    }
    printf(" %s\n", bufferLine);

}

在原始源代码上运行并与系统 xxd 的输出进行比较时,没有差异。我还对照一个只有 16 个字符的文件(abcdefghijklmno 加一个换行符)检查了它;那里的输出也是一样的。我检查了它自己的二进制文件——发现并修复了零字节和未通知的提前退出问题。

关于一个简单的 C 程序是否可以模仿默认的 'xxd' 命令,使其 diff 输出返回 0?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54500648/

相关文章:

git - windows上的Git Bash如何退出 'git diff'的结果?

c - 编译为 cortex-m0 时,unsigned int 不是 uint32_t——可能是 C 编译器标志问题

c - 重写温度转换程序

功能代码

java - 整数.parseInt : 0xff80CBC4 is an invalid int

windows - Dropbox 是如何实现这两个功能的(更改图标和仅发送文件更改的差异。)

c - 编写用于 R 的 C 函数时究竟需要保护什么

c - 在C中以十六进制读取文件内容

linux - 如何通过 Ubuntu 中的脚本将十进制数转换为十六进制数

linux - 存在完整路径时,如何使用补丁在不同文件夹上为文件夹应用差异文件?