【问题标题】:Print binary representation of file打印文件的二进制表示
【发布时间】:2023-03-03 23:14:01
【问题描述】:

我需要一个函数,它可以打印出读取文件的二进制表示,例如 unix 中的 xxd 程序,但我想自己制作。十六进制与 %x 一起工作得很好,但没有内置的二进制格式。有人知道怎么做吗?

【问题讨论】:

  • What have you tried?。如果您正在寻找想法,只需执行与十六进制转储相同的操作,但在输出生成中添加一个中间步骤以转换十六进制字节输出并将其转换为位表示。请注意,每个字节在屏幕上需要 8 个字符(一串零和一)。每行 8 个字节,每个字节之间有一个空格分隔符,您需要 71 列显示空间

标签: c unix binary printf hexdump


【解决方案1】:

我通常不相信用完整的代码实现来回答这类问题,但是很多年前我收到了这段代码,我觉得有义务把它传递下去。除了用法之外,我已经删除了所有的 cmets,所以你可以自己尝试弄清楚它是如何工作的。

代码 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 并将 printf ("%02x ", (unsigned char) str [j]); 替换为:

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

所需的更改非常简单,您只需单独移动八位字节的所有 8 位并屏蔽除最不重要的位之外的所有位。请记住以一开始似乎违反直觉的顺序执行此操作,因为我们从左到右打印。

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

Size:  512
 00000000 00000000 00000000  -  00100000 01100110 01110100  -  ... ft
 01111001 01110000 01101001  -  01110011 01101111 01101101  -  ypisom
 00000000 00000000 00000010  -  00000000 01101001 01110011  -  ....is
 01101111 01101101 01101001  -  01110011 01101111 00110010  -  omiso2
 01100001 01110110 01100011  -  00110001 01101101 01110000  -  avc1mp
 00110100 00110001 00000000  -  00000110 11101000 11100110  -  41....
 01101101 01101111 01101111  -  01110110 00000000 00000000  -  moov..
 00000000 01101100 01101101  -  01110110 01101000 01100100  -  .lmvhd
 00000000 00000000 00000000  -  00000000 01111100 00100101  -  ....|%
 10110000 10000000 01111100  -  00100101 10110000 10000000  -  ..|%..
 00000000 00000000 00000011  -  11101000 00000000 00001100  -  ......

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

【讨论】:

  • 到目前为止,我了解您的代码机制,但函数转储中的“数据”和“伦”参数究竟是什么?我假设 data 是要解释的读取数据(要转换的文件)和 len 作为数据的大小?但如果你能清楚地告诉我,我将不胜感激,所以我不做任何假设
  • data 只是一个指向你要转储的内存的指针(因为它是void*,它可以指向任何东西),而len 是你要转储的长度(以字节为单位)想倾倒。内存可能比len 大得多,这只是您实际想要打印的长度 - 想象一下尝试打印一个 1 GiB 的文件,打印到控制台需要很长时间,所以您通常希望一次只打印一小部分数据。您仍然需要自己打开并读取文件才能使用此功能,一旦您拥有该功能,您就可以传递指向数据的指针以及要打印的数据量。
【解决方案2】:

根据语言的不同,假设您有位运算,可以对变量的每一位进行操作,您可以执行以下操作。将文件读入缓冲区或一行,如果需要编码,现在强制它扩展 ASCII(8 位/ 1 字节字符),当你得到缓冲区时,你从 7 循环到 0 并使用 and 按位和 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;
}

【讨论】:

  • 顺便说一下,代码没有经过测试,但它应该可以工作,当然需要 stdio 和 iostream 库。
猜你喜欢
  • 2013-08-22
  • 1970-01-01
  • 1970-01-01
  • 2021-05-25
  • 2023-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-27
相关资源
最近更新 更多