Чтение содержимого из файла .bin в C Ошибка при первом значении фреда - PullRequest
0 голосов
/ 17 апреля 2020

У меня возникли проблемы с функцией фреда. все читается хорошо, но мой инструмент проверки ошибок отключается по первому значению fread, и я абсолютно не знаю, почему.

, если я перезаписался в начале файла, и он правильно печатает мое значение тогда что не удалось?

int main()
{
   FILE *BinFile;
   //FILE *CopyBinFile;

  // printf("Enter name of a file you wish to see\n");
   //gets(file_name);

   if ((BinFile = fopen("C:/Users/Tom/OneDrive/Desktop/out.bin","rb")) == NULL){
       printf("Error, shits broke");
       exit(1);
   }

    fseek(BinFile,0,SEEK_END); 
    SizeofFile = ftell(BinFile);

   printf("The contents of out.bin file are:\n");
   printf("the size of the file is %d \n", SizeofFile);

    //fseek(BinFile,0,SEEK_SET ); // point back to the start
    rewind(BinFile);

    if (fread(&Buffer4Can, sizeof(uint8_t) , SizeofFile ,BinFile) != 1){ //**<<<<--- this**
        printf("err \n");
    }

    for(c=0;c<SizeofFile;c++){
    printf("%02X ", Buffer4Can[c]);
    count++;
    if (count == 8){
        printf(" \n");
        count =0;
    }   
 }

   return 0;
}

ОБНОВЛЕНО: @ Спасибо всем за помощь! Я действительно ценю это. смог перенести его в stmIDE приятно и намного проще, так как он выглядит более упорядоченным в библиотеке st *

if ( f_mount(&MyFatFs, SDPath, 1)== FR_OK){
     HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12);    //

    if( f_open(&myFILE, "out.bin", FA_READ) == FR_OK ){
        HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_13); //ORANGE
     }

    // get byte amount from file
    //f_lseek(&myFILE, 0x20);
    SizeofFile=f_size(&myFILE);
    //f_rewind(&myFILE);

    //SizeofFile=11240;
    //store data into buffer
    if (f_read(&myFILE, &Buffer4Can, SizeofFile, &byteCounter)== FR_OK){

    }
    HAL_Delay(2000);
        //toggle
        HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_14);

        //untoggle
        HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12);
        HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_13); //orng led
 }

 if(byteCounter==0){ /* error or eof */
  HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_15); // blue LED
 }

Ответы [ 2 ]

2 голосов
/ 17 апреля 2020

У вас есть ряд тонких ошибок, а затем вы проверяете возвращаемое значение fread против неправильного значения. При вызове fread нет необходимости ставить перед Buffer4Can оператор & ( адрес ). Buffer4Can является массивом и будет преобразован в указатель на первый элемент при доступе (см .: Стандарт C11 - 6.3.2.1 Другие операнды - L-значения, массивы и обозначения функций (p3) )

Когда вы берете адрес Buffer4Can, вы меняете тип указателя на fread с uint8_t* (без &) на uint8_t (*)[120000)& тип становится указатель на массив из uint8_t[120000]). Теперь, по счастливому совпадению, Buffer4Can является массивом, и указатель на uint8_t и * указатель на массив uint8_t[120000] оба будут преобразованы в один и тот же адрес (но имеют совершенно разные типы).

Поскольку они разрешаются по одному и тому же адресу и поскольку fread() принимает параметр void* в качестве первого параметра, ошибка остается незаметно для пользователя. (Достаточно сказать, что если вы попытались fread (&Buffer4Can + 1, ..., то вещи не сработали бы хорошо ...)

Другая проблема, на которую указал @ Domeni c, - это сравнение возврата fread(). Прототип для fread():

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

Где возвращаемое значение для fread():

   On success, fread() and fwrite() return the number of items read or
   written.  This number equals the number of bytes transferred only
   when size is 1.

См. man 3 fread

В вашем случае вы предоставляете sizeof(uint8_t) для параметра size функции, означающей возврат "This number equals the number of bytes transferred" или SizeofFile в вашем случае. Кроме того, точно так же, как sizeof (char), sizeof (uint8_t) равно 1, поэтому его можно просто представить как 1.

Единственная другая область, где вам не хватает проверки, - до fread(), вы необходимо подтвердить SizeofFile <= 120000, чтобы защитить границы вашего массива. Вы можете положить это вместе со своим вызовом на fread() как:

    if (MAXB < SizeofFile ||   /* protect bounds/compare return to SizeofFile */
        fread (Buffer4Can, 1, SizeofFile, fp) != (size_t)SizeofFile) {
        fputs ("error: file exceeds buffer size, or fread failed.\n", stderr);
        return 1;
    }

( note: тип возврата для fread() - size_t, поэтому приведение SizeofFile необходимо избегать сравнения значений со знаком и без знака)

При использовании типов с точной шириной макросы, используемые как для преобразования ввода, так и для вывода, предоставляются в inttypes.h (включая саму stdint.h). Макрос для вывода значения unit8_t в шестнадцатеричном формате - PRIx8. Чтобы вывести 8 двухзначных шестнадцатеричных значений на строку, перед которыми стоит "0x", вы можете сделать:

    for (int i = 0; i < (int)SizeofFile; i++) {     /* loop over bytes */
        if (i && i % 8 == 0)                        /* output 8 per-line */
            putchar ('\n');
        printf (" 0x%02" PRIx8, Buffer4Can[i]);     /* use exact width specier */
    }
    putchar ('\n');             /* tidy up with newline */

( note: макрос PRIx8 находится вне кавычек часть строки формата , она стоит одна. Если бы вы хотели новую строку в конце, строка формата была бы " 0x%02" PRIx8 "\n")

С то, что вы программируете, должно функционировать по вашему желанию. Обратите внимание, что имя файла для чтения требуется в качестве первого аргумента программы, или, если ничего не указано, оно будет считано из stdin по умолчанию (вы можете перенаправить двоичный файл в stdin). В целом, вы можете сделать что-то похожее на:

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>

#define MAXB 120000     /* if you need a constant, #define one (or more) */

int main (int argc, char **argv) {

    uint8_t Buffer4Can[MAXB];   /* buffer to hold bytes from file */
    long SizeofFile;            /* size of file (note type long for ftell) */
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "rb") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    fseek (fp, 0, SEEK_END);    /* seek end */
    SizeofFile = ftell(fp);     /* get lenght */
    rewind (fp);                /* rewind to beginning */

    if (MAXB < SizeofFile ||   /* protect bounds/compare return to SizeofFile */
        fread (Buffer4Can, 1, SizeofFile, fp) != (size_t)SizeofFile) {
        fputs ("error: file exceeds buffer size, or fread failed.\n", stderr);
        return 1;
    }
    if (fp != stdin)   /* close file if not stdin */
        fclose (fp);

    for (int i = 0; i < (int)SizeofFile; i++) {     /* loop over bytes */
        if (i && i % 8 == 0)                        /* output 8 per-line */
            putchar ('\n');
        printf (" 0x%02" PRIx8, Buffer4Can[i]);     /* use exact width specier */
    }
    putchar ('\n');             /* tidy up with newline */
}

( note: все лишние переменные удалены, и обратите внимание, что тип возвращаемого значения для ftell() равен long, не int)

Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.

1 голос
/ 18 апреля 2020

относительно:

if (fread(&Buffer4Can, sizeof(uint8_t), SizeofFile ,BinFile) != 1)

буфер Buffer4Can является именем массива и ссылается на «пустое» имя массива, ухудшенное до адреса первого байта массива. Следовательно, добавление & является ошибкой.

Существует также проблема с параметром: SizeofFile, так как функция ожидает параметр с типом size_t. Предложить:

if (fread(Buffer4Can, sizeof(uint8_t), (size_t)SizeofFile, BinFile ) != (size_t)SizeofFile)

Функция fread() возвращает количество прочитанных «элементов». В текущем операторе размер каждого элемента равен 1, поэтому успешная операция чтения вернет третий параметр, поэтому вместо сравнения возвращаемого значения с 1 следует сравнивать с (size_t)SizeofFile

На странице MAN для fread()

В случае успеха fread () и fwrite () возвращают количество прочитанных или записанных элементов. Это число равно количеству байтов, переданных, только когда размер равен 1. Если возникает ошибка или достигнут конец файла, возвращаемое значение представляет собой короткий счетчик элементов (или ноль).

Обратите внимание на возвращаемые типы и типы параметров и дайте функциям то, что они ожидают.

...