hexdump输出与xxd输出

时间:2014-10-10 14:01:40

标签: c xxd

我试图像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列中的十六进制数字。

我试图编辑&#34; 10&#34;在下面的源代码中,类似于&#34; 12&#34;但它在输出中产生错误,似乎是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;
 }

1 个答案:

答案 0 :(得分:0)

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

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

我有一些乐趣,可以找出神奇的公式来正确居中文本Bytes并计算分隔符显示的破折号数。其余的非常简单。

除了你的单行示例之外,我不知道xxd输出是什么样的,所以我使用stat提前读出文件的长度(添加了一个有机会显示错误&#34;不是文件&#34; - 例如尝试使用文件夹)并显示正确数量的破折号和空格以排列行计数器。我将此值设置为最小值为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...