简体   繁体   中英

Reading content from .bin file in C Error on first fread value

i've been having some issue with my fread function. everything reads nicely but my error checker goes off on the first value of fread and i have absolutely no idea to as why.

if i've rewinded back to the begining of the file, and it prints my value correctly then what failed?

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;
}

UPDATED: @ Thanks everyone for the help. i really do appreciate it. was able to port it to stmIDE nicely and alot easier as it seems to be alot more streamlined in the library st provides

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
 }

You have a number of subtle errors and then are checking the return of fread against an improper value. In your call to fread , there is no need to precede Buffer4Can with the & ( address of ) operator. Buffer4Can is an array, and will be converted to a pointer to the first element on access (see: C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3) )

When you take the address of Buffer4Can you change the pointer type you provide to fread from uint8_t* (without the & ) to uint8_t (*)[120000) (with the & the type becomes a pointer-to-array-of uint8_t[120000] ). Now by happy coincidence being that Buffer4Can is an array, both the pointer-to uint8_t and *pointer-to-array-of uint8_t[120000] will both resolve to the same address (but are of vastly different types).

Since they resolve to the same address and since fread() takes a parameter of void* for its first parameter, the error goes silently unnoticed. (suffice it to say if you attempted fread (&Buffer4Can + 1, ... things would not work out well...)

The other issue pointed out by @Domenic is your comparison of the fread() return. The prototype for fread() is:

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

Where the return value for fread() is:

 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.

See man 3 fread

In your case you provide sizeof(uint8_t) for the size parameter of the function meaning for the return "This number equals the number of bytes transferred" or SizeofFile in your case. Further, just like sizeof (char) , sizeof (uint8_t) is 1 so it can simply be represented as 1 .

The only other area where you are missing a validation is prior to fread() , you must confirm SizeofFile <= 120000 to protect your array bounds. You can put that together with your call to fread() as:

    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: the return type for fread() is size_t so a cast of SizeofFile is necessary to avoid comparison between signed and unsigned values)

When using exact-width types, the macros to use for both input and output conversion are provided in inttypes.h (which includes stdint.h itself) The macro for output of a unit8_t value in hex-format is PRIx8 . To output 8 2-char hex-values per-line preceded by "0x" , you could do:

    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: the PRIx8 macro is not within the quoted part of the format-string , it stands alone. If you had wanted a newline at the end, the format-string would be " 0x%02" PRIx8 "\n" )

With that you program should function as desired. Note, it takes the filename to read as the first argument to the program, or if none is provided, it will read from stdin by default (you can redirect a binary file on stdin ). Putting it altogether, you could do something similar to:

#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: all superfluous variables have been removed, and note the return type for ftell() is long , not int )

Look things over and let me know if you have further questions.

regarding:

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

the buffer Buffer4Can is an array name and referencing a 'bare' array name degraded to the address of the first byte of the array. Therefore, prepending a & is an error.

There is also a problem with the parameter: SizeofFile as the function is expecting a parameter with type size_t . Suggest:

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

The fread() function returns the number of 'items' read. In the current statement, the size of each item is 1 , so a successful read operation will return the third parameter, so instead of comparing the returned value to 1 should be comparing to (size_t)SizeofFile

From the MAN page for 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. If an error occurs, or the end of the file is reached, the return value is a short item count (or zero).

Please pay attention to returned types and parameter types and give functions what they are expecting.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM