C编程:如何从二进制文件中读取并打印字节?

4
我希望打开一个二进制文件,读取文件的第一个字节,最后将十六进制值(以字符串格式)打印到标准输出(stdout)上(例如,如果第一个字节为03 hex,则我希望打印出0x03)。但是我得到的输出与我的样本二进制文件中所知道的不符,因此我想知道是否有人可以帮助解决这个问题。
以下是代码:
#include <stdio.h>
#include <fcntl.h>

int main(int argc, char* argv[])
{
int fd;
char raw_buf[1],str_buf[1];

fd = open(argv[1],O_RDONLY|O_BINARY);

    /* Position at beginning */
lseek(fd,0,SEEK_SET);

    /* Read one byte */
read(fd,raw_buf,1);

    /* Convert to string format */
sprintf(str_buf,"0x%x",raw_buf);
printf("str_buf= <%s>\n",str_buf);

close (fd);
return 0;   
}

程序编译如下: gcc rd_byte.c -o rd_byte

并如下运行: rd_byte BINFILE.bin

已知样本二进制文件的第一个字节为03,我得到以下输出: str_buf= <0x22cce3>

我期望的是 str_buf= <0x03>

我的代码哪里出错了? 感谢任何帮助。

1
Nick的答案是正确的。 另外,lseek是不必要的(文件在fopen后从零开始),你可以直接printf该值,而不是先将其打印到字符串中 - 即printf(“0x%x”,raw_buf [0])。如果您始终希望以两个数字打印,请改用%02x。此外,请确保将raw_buf声明为unsigned char以避免符号扩展。 - Matthias Wandel
5个回答

8

您正在打印指针 raw_buf 的值,而不是该位置的内存:

sprintf(str_buf,"0x%x",raw_buf[0]);

正如Andreas所说,str_buf也不够大。但是:不需要第二个缓冲区,您可以直接调用printf
printf("0x%x",raw_buf[0]);

我更喜欢使用printf("0x%.02x",raw_buf[0]);,这样它可以打印每个字节输入的相同大小。 - Douglas L

5
我认为你把事情复杂化了,并在不必要的地方使用了不可移植的结构。您只需执行以下操作即可:

#include <stdio.h>

int main(int argc, char** argv)
{
    if (argc < 2)
        return 1; /* TODO: better error handling */

    FILE* f = fopen(argv[1], "rb");

    /* TODO: check f is not NULL */

    /* Read one byte */    
    int first = fgetc(f);

    if (first != EOF)
        printf("first byte = %x\n", (unsigned)first);

    /* TODO else read failed, empty file?? */

    fclose(f);

    return 0;
}

5

越简单越好...

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char* argv[]) {
    int fd;
    unsigned char c;

    /* needs error checking */
    fd = open(argv[1], O_RDONLY);
    read(fd, &c, sizeof(c));
    close(fd);

    printf("<0x%x>\n", c);
    return 0;
}
  1. 不需要使用“seek”
  2. 如果您想读取一个字节,请使用“unsigned char”
  3. “printf”会做格式化处理

2
我认为也需要使用close(fd); - M.Kumaran

2

str_buf最大只能容纳1个字节(char str_buf[1];),它的长度应至少为5个字节(4个字节用于XxXX,再加上\0)。

另外,更改

sprintf(str_buf,"0x%x",raw_buf);

为了

sprintf(str_buf,"0x%x",*raw_buf);

否则,你将打印raw_buf指针的地址,而不是通过解引用指针获得的值。
最后,请确保raw_buf都是无符号的。标准规定字符的符号(未明确指定的情况下)是实现定义的,即每个实现都决定它们是否应该有符号。在实践中,除非使用特定的标志进行编译,否则大多数实现默认为有符号。处理字节时,请确保它们是无符号的;否则,如果您想将它们转换为整数,您将得到令人惊讶的结果。

0

利用上面各位的回答(非常感谢!),我想发布这段代码,这是我最终使用的简化版本。

然而,以下代码所做的事情与我的原始问题描述有所不同:该代码不会像最初描述的那样读取二进制文件头的第一个字节,而是读取输入二进制文件(.DBF 文件)的第 11 和第 12 个字节(偏移量为 10 和 11)。第 11 和第 12 个字节包含数据记录的长度(实际上这就是我想知道的内容),其中最低有效字节位于第一位:例如,如果第 11 和第 12 个字节分别为:0x06 0x08,则数据记录的长度将为 0x0806 字节,或者在十进制中为 2054 字节。

 #include <stdio.h>
 #include <fcntl.h>

 int main(int argc, char* argv[]) {
 int fd, dec;
 unsigned char c[1];
 unsigned char hex_buf[6];

 /* No error checking, etc. done here for brevity */

 /* Open the file given as the input argument */
 fd = open(argv[1], O_RDONLY);

 /* Position ourselves on the 11th byte aka offset 10 of the input file */
 lseek(fd,10,SEEK_SET);

 /* read 2 bytes into memory location c */
 read(fd, &c, 2*sizeof(c));

 /* write the data at c to the buffer hex_buf in the required (reverse) byte order + formatted */
 sprintf(hex_buf,"%.2x%.2x",c[1],c[0]);
 printf("Hexadecimal value:<0x%s>\n", hex_buf);

 /* copy the hex data in hex_buf to memory location dec, formatting it into decimal */
 sscanf(hex_buf, "%x", &dec);

 printf("Answer: Size of a data record=<%u>\n", dec);

 return 0;

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接