打印文件的二进制表示

时间:2013-09-12 01:27:16

标签: c unix binary printf hexdump

我需要一个函数,它会在unix中打印出像xxd程序这样的读取文件的二进制表示,但是我想创建自己的函数。使用%x时,十六进制可以正常工作,但二进制没有内置格式。有谁知道怎么做?

2 个答案:

答案 0 :(得分:1)

我通常不相信用完整的代码实现回答这些问题,但是多年前我就把这段代码交给了我,我觉得有义务将它传递给我。除了用法之外,我已删除了所有注释,因此您可以尝试自己弄清楚它是如何工作的。

代码 base 16

#include <stdio.h>
#include <ctype.h>

// Takes a pointer to an arbitrary chunk of data and prints the first-len bytes.
void dump (void* data, unsigned int len)
{
  printf ("Size:  %d\n", len);

  if (len > 0) {
    unsigned width = 16;
    char *str = (char *)data;
    unsigned int j, i = 0;

    while (i < len) {
      printf (" ");

      for (j = 0; j < width; j++) {
        if (i + j < len)
          printf ("%02x ", (unsigned char) str [j]);
        else
          printf ("   ");

        if ((j + 1) % (width / 2) == 0)
          printf (" -  ");
      }

      for (j = 0; j < width; j++) {
        if (i + j < len)
          printf ("%c", isprint (str [j]) ? str [j] : '.');
        else
          printf (" ");
       }

       str += width;
       i += j;

      printf ("\n");
    }
  }
}


输出 base 16 (摘录自flash视频的前512字节*)

Size:  512
 00 00 00 20 66 74 79 70  -  69 73 6f 6d 00 00 02 00  -  ... ftypisom....
 69 73 6f 6d 69 73 6f 32  -  61 76 63 31 6d 70 34 31  -  isomiso2avc1mp41
 00 06 e8 e6 6d 6f 6f 76  -  00 00 00 6c 6d 76 68 64  -  ....moov...lmvhd
 00 00 00 00 7c 25 b0 80  -  7c 25 b0 80 00 00 03 e8  -  ....|%..|%......
 00 0c d6 2a 00 01 00 00  -  01 00 00 00 00 00 00 00  -  ...*............
 00 00 00 00 00 01 00 00  -  00 00 00 00 00 00 00 00  -  ................
 00 00 00 00 00 01 00 00  -  00 00 00 00 00 00 00 00  -  ................
 00 00 00 00 40 00 00 00  -  00 00 00 00 00 00 00 00  -  ....@...........
 00 00 00 00 00 00 00 00  -  00 00 00 00 00 00 00 00  -  ................
 00 01 00 02 00 01 9f 38  -  74 72 61 6b 00 00 00 5c  -  .......8trak...\


我假设您已经知道如何判断文件的大小并以二进制模式读取文件,因此我将其排除在讨论之外。根据您的终端宽度,您可能需要调整变量:width - 该代码目前设计用于80个字符终端。

我还假设当你提到xxd和“二进制”时你的意思是非文本而不是基数2.如果你想要基数2,请将width设置为6并替换{ {1}}这个:

printf ("%02x ", (unsigned char) str [j]);

所需的更改非常简单,您只需要单独移动八位字节的所有8位并屏蔽除最低位之外的所有位。因为我们从左到右打印,所以请记住最初看起来反直觉的顺序。

输出 base 2 (摘录自flash视频的前512字节*)

{
  for (int k = 7; k >= 0; k--)
    printf ("%d", ((unsigned char)str [j] >> k) & 1);
  printf (" ");
}

*为简单起见,让我们假设一个字节总是8位。

答案 1 :(得分:0)

根据语言的不同,假设您有按位操作(允许您对变量的每个位进行操作),您可以执行以下操作。将文件读入缓冲区或行,如果需要编码,现在将其强制为扩展ASCII(8位/ 1字节字符),当你获得缓冲区时,从7循环到0并使用和按位和a切换到检查每个位值,让我举一个C:

的例子
// gcc -Wall -Wextra -std=c99 xxd.c
#include <stdio.h>
#include <string.h>

int main() {
  // Whatever buffer size you chose.
  char buffer[32];
  //Feel free to replace stdin to a File Pointer, or any other stream
  // Reading into a char, means reading each byte at once
  while (!feof(stdin)) {
    // Read at most buffer bytes. Since its ASCII 1 byte = 1 char.
    fgets(buffer, sizeof(buffer), stdin);
    // Iterate though each character in the string/buffer.
    const size_t len = strlen(buffer);
    for (size_t j = 0; j < len; j++) {
      // Print the most significant bit first.
      for (int i = 7; i >=0; i--) {
        // Check if the i-th bit is set
        printf(buffer[j] & (1 << i) ? "1" : "0");
      }
    }
  }

  return 0;
}