gpt4 book ai didi

c - hexdump 输出与 xxd 输出

转载 作者:行者123 更新时间:2023-11-30 17:27:43 30 4
gpt4 key购买 nike

我正在尝试创建像 xxd 这样的十六进制转储,但我正在尝试解决一些差异。目前,程序每行处理 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) 我还希望程序在 4 行的列中列出十六进制数字,就像 xxd 中一样。

我尝试将下面源代码中的“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;
}

最佳答案

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

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

我很有趣地找出了正确居中文本字节的神奇公式,并计算了分隔符要显示的破折号。其余部分非常简单。

除了你的一行示例之外,我不知道 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...

关于c - hexdump 输出与 xxd 输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26301273/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com