Программирование на C: как прочитать и распечатать байт из двоичного файла? - PullRequest
4 голосов
/ 08 января 2010

Я хочу открыть двоичный файл, прочитать первый байт файла и, наконец, напечатать шестнадцатеричное значение (в строковом формате) в стандартный вывод (т. Е. Если первый байт 03 шестнадцатеричный, я хочу распечатать 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>

Где ошибка в моем коде?

Спасибо за любую помощь.

Ответы [ 5 ]

7 голосов
/ 08 января 2010

Вы печатаете значение указателя raw_buf, а не память в этом месте:

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

Как сказал Андреас, str_buf тоже недостаточно велик. Но: нет необходимости во втором буфере, вы можете просто позвонить printf напрямую.

printf("0x%x",raw_buf[0]);
5 голосов
/ 08 января 2010

Меньше значит больше ...

#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 сделает формат
4 голосов
/ 08 января 2010

Я думаю, что вы слишком усложняете вещи и используете непереносимые конструкции, когда они на самом деле не нужны.

Вы должны просто сделать:

#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;
}
2 голосов
/ 08 января 2010

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 unsigned. В стандарте указано, что сигнатура символов (если это не указано явно) определяется реализацией, т. Е. Каждая реализация решает, должны ли они быть подписаны или нет. На практике в большинстве реализаций они подписываются по умолчанию, если вы не компилируете с определенным флагом. При работе с байтами всегда убедитесь, что они не подписаны; в противном случае вы получите удивительные результаты, если захотите преобразовать их в целые числа.

0 голосов
/ 15 января 2010

Используя информацию из различных ответов выше (спасибо всем!), Я хотел бы опубликовать этот фрагмент кода, который является урезанной версией того, что я наконец-то использовал.

Однако есть разница между тем, что делает следующий код, и тем, что было описано в моем исходном вопросе: этот код не читает первый байт заголовка двоичного файла, как описано первоначально, а вместо этого читает 11-й и 12-й байты (смещения 10 и 11) входного двоичного файла (файл .DBF). 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;

}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...