【问题标题】:hexdump output vs xxd outputhexdump 输出与 xxd 输出
【发布时间】:2014-10-10 14:01:39
【问题描述】:

我正在尝试创建一个类似于 xxd 的 hexdump,但我正在尝试解决一些差异。目前,该程序每行处理 10 个字符,如最右列所示,而 xxd 中为 16 个。它也只显示每列 1 个八位字节,而不是成对的 2 个八位字节。

xxd

 0000000: 2369 6e63 6c75 6465 203c 7374 6469 6f2e  #include <stdio.

我的输出

 0:  23 69 6E 63 6C 75 64 65 20 3C  #include <     

编辑:

为了添加一些说明,我试图实现两件事。 1) 我希望这个程序能够像 xxd 一样输出完全。为此,它需要输出 32 个十六进制数字(8x 列,每列 4)。 2)我还希望程序在 xxd 中列出行的 4 列中的十六进制数字。

我尝试将下面源代码中的“10”编辑为类似于“12”的内容,但它会在输出中产生错误,它似乎是 magic number

来源:

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

 #define BYTE_OFFSET_INIT 8
 #define CHAR_OFFSET_INT  39
 #define LINE_LENGTH 50

 static void print_e(int e, char *program, char *file)
 {
   fprintf(stderr, "%s: %s: %s\n", program, file, strerror(e));
 }
 static void print_line(char *line)
 {
   int i;  
 /* sprintf leaves terminators mid-line, so clear them out so we can print the full line */
   for (i = BYTE_OFFSET_INIT; i < CHAR_OFFSET_INT; i++)
     if (line[i] == '\0')
       line[i] = ' ';
   printf("%s\n", line);
 }

 int main(int argc, char *argv[])
 {
   char line[LINE_LENGTH + 1];

   int ch;
   int character = 0;
   int line_offset = 0;
   int byte_offset = BYTE_OFFSET_INIT, char_offset = CHAR_OFFSET_INT;

   if (argc != 2) {
     fprintf(stderr, "Usage: %s [file]\n", argv[0]);
     exit(EXIT_FAILURE);
   }
   FILE *fp = fopen(argv[1], "rb");
   if (!fp) {
     print_e(errno, argv[0], argv[1]);
     exit(EXIT_FAILURE);
   }

   printf("Offset              Bytes              Characters\n");
   printf("------  -----------------------------  ----------\n");

   while ((ch = fgetc(fp)) != EOF) {
     if (character == 0) {
       sprintf(line, "%6d  ", line_offset);
       line_offset += 10;
     }
     sprintf(line + byte_offset, "%02X ", ch);
     sprintf(line + char_offset, "%c", isprint(ch) ? ch : '.');
     character++;
     char_offset++;
     byte_offset += 3;

     if (character == 10) {
       print_line(line);
       character = 0;
       char_offset = CHAR_OFFSET_INT;
       byte_offset = BYTE_OFFSET_INIT;
     }
   }
   if (ferror(fp)) {
     print_e(errno, argv[0], argv[1]);
     exit(EXIT_FAILURE);
   }

   if (character > 0)
     print_line(line);

   if (fclose(fp) == EOF) {
     print_e(errno, argv[0], argv[1]);
     exit(EXIT_FAILURE);
   }
   return 0;
 }

【问题讨论】:

  • 是的。而且,你的问题是? (提示:“10”和每个字节值后面的空格都在您的程序中,如果那真的是您的源,那么修复应该很简单......)
  • @paxdiablo 我已经将回调、hexdump 和 main 函数合并到一个文件中,但我无法编译它——“'hexDump' 的类型冲突
  • @DevSolar 我无法将程序扩展为处理 16 个字符而不是 10 个任何进一步的提示?源中的数字“10”似乎是一个神奇的数字。
  • “幻数”10是\n的ASCII码。

标签: c xxd


【解决方案1】:

虽然可以一次扫描一个字节并将其写入输出字符串的正确位置,但这绝不是必要的。一次读取DISPLAY_LENGTH 字节并循环读取两次读取的字节数要容易得多;首先输出十六进制表示,然后再次输出 ASCII 字符。唯一的(次要)警告是在文件末尾做什么;但由于fread 返回字符数,您可以继续计算并输出空格,只要需要填充十六进制行即可。

这导致以下程序。 DISPLAY_LENGTH 是每行显示的总字节数,GROUP_BYTES 是每个十六进制组中的单个字节数(将其设置为 1 将显示“常规”间隔十六进制输出,2 将分组为在您的 xxd 示例中,更高的值也应该有效)。

我找到了一些神奇的公式来正确地将文本 Bytes 居中并计算要为分隔符显示多少个破折号。其余的都非常简单。

我不知道xxd 的输出是什么样的,除了你的单行示例,所以我使用stat 提前读出文件的长度(增加了显示错误的机会“不是文件”——例如尝试使用文件夹)并显示正确数量的破折号和空格以排列行计数器。我将此值设置为至少 6,因此文本Offset 始终有空间。

如果您的编译器不是现代编译器,它可能会抱怨%zu 格式字符串。如果是这样,请使用%lu;您可能还需要将所有出现的size_t 更改为unsigned long

#include <stdio.h>    
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>

#define DISPLAY_LENGTH  21
#define GROUP_BYTES     2

static void print_e(int e, char *program, char *file)
{
    fprintf(stderr, "%s: %s: %s\n", program, file, strerror(e));
}

int main(int argc, char *argv[])
{
    size_t i;
    struct stat fs;
    int n_digit;
    unsigned char read_buf[DISPLAY_LENGTH];
    size_t bytes_read, cpos = 0;

    if (argc != 2)
    {
        fprintf(stderr, "Usage: %s [file]\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    FILE *fp = fopen(argv[1], "rb");
    if (!fp)
    {
        print_e (errno, argv[0], argv[1]);
        exit(EXIT_FAILURE);
    }

    if (stat(argv[1], &fs) == -1)
    {
        print_e (errno, argv[0], argv[1]);
        exit(EXIT_FAILURE);
    }

    if ((fs.st_mode & S_IFMT) != S_IFREG)   /* regular file */
    {
        fprintf(stderr, "Not a regular file: %s\n", argv[1]);
        exit(EXIT_FAILURE);
    }

    n_digit = 0;
    while (fs.st_size > 0)
    {
        fs.st_size /= 10;
        n_digit++;
    }
    if (n_digit < 6)
        n_digit = 6;

    printf("%*s  ", n_digit, "Offset");
    printf("%*s%-*s", ((2*DISPLAY_LENGTH+(DISPLAY_LENGTH+GROUP_BYTES-1)/GROUP_BYTES)+2)/2, "Bytes", ((2*DISPLAY_LENGTH+(DISPLAY_LENGTH+GROUP_BYTES-1)/GROUP_BYTES)+2-5)/2, "");
    printf ("  Characters\n");
    for (i=0; i<n_digit; i++)
        printf ("-");

    printf("  ");

    for (i=1; i<2*DISPLAY_LENGTH+(DISPLAY_LENGTH+GROUP_BYTES-1)/GROUP_BYTES; i++)
        printf ("-");
    printf ("  ");

    for (i=0; i<DISPLAY_LENGTH; i++)
        printf ("-");
    printf ("\n");

    while ( (bytes_read = fread (read_buf, 1, DISPLAY_LENGTH, fp)))
    {
        printf ("%*zu ", n_digit, cpos);

        for (i=0; i<bytes_read; i++)
        {
            if (!(i % GROUP_BYTES))
                printf (" ");
            printf ("%02X", read_buf[i]);
        }
        while (i < DISPLAY_LENGTH)
        {
            if (!(i % GROUP_BYTES))
                printf (" ");
            printf ("  ");
            i++;
        }

        printf ("  ");

        for (i=0; i<bytes_read; i++)
            printf ("%c", isprint(read_buf[i]) ? read_buf[i] : '.');

        printf ("\n");

        cpos += bytes_read;
    }
    if (ferror(fp))
    {
        print_e (errno, argv[0], argv[1]);
        exit(EXIT_FAILURE);
    }

    if (fclose(fp))
    {
        print_e (errno, argv[0], argv[1]);
        exit(EXIT_FAILURE);
    }
    return 0;
}

示例输出,显示它自己编译的可执行文件,显示长度为 21,每 2 个字节分组:

Offset                        Bytes                           Characters
------  ----------------------------------------------------  ---------------------
     0  CFFA EDFE 0700 0001 0300 0080 0200 0000 0D00 0000 70  ....................p
    21  0600 0085 0020 0000 0000 0019 0000 0048 0000 005F 5F  ..... .........H...__
    42  5041 4745 5A45 524F 0000 0000 0000 0000 0000 0000 00  PAGEZERO.............
... (673 very similar lines omitted) ...
 14196  7075 7473 005F 7374 6174 2449 4E4F 4445 3634 005F 73  puts._stat$INODE64._s
 14217  7472 6572 726F 7200 6479 6C64 5F73 7475 625F 6269 6E  trerror.dyld_stub_bin
 14238  6465 7200 0000                                        der...

【讨论】:

  • 非常感谢,我印象非常深刻。您可以在几乎任何 linux shell 中运行 xxd,因为它自带。我可能会回来询问有关您的代码的问题,希望您不介意:)。先生,晚安。
  • 你是对的,因为它似乎也在我的 Mac (OS X) 上!哦,好吧,我写这些东西已经很久了,所以还是没问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-25
  • 1970-01-01
  • 2015-09-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多