在第一个 fread 值上从 C 错误中的 .bin 文件中读取内容

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

我的恐惧函数一直有问题。 一切都很好,但我的错误检查器在 fread 和 i 的第一个值上关闭 完全不知道为什么。

如果我倒回到文件的开头,并且它正确地打印了我的值,那是什么失败了?

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
 }

您有一些细微的错误,然后正在检查 fread 的 return 与不正确的值。在您对 fread 的调用中,无需在 Buffer4Can 之前使用 &address of )运算符。 Buffer4Can 是一个数组,访问时将转换为指向第一个元素的指针(参见:C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3)

当您获取 Buffer4Can 的地址时,您将提供给 fread 的指针类型从 uint8_t*(没有 &)更改为 uint8_t (*)[120000) (使用 & 类型变为 指向数组的指针 uint8_t[120000])。现在巧合的是 Buffer4Can 是一个数组, pointer-to uint8_t 和 *pointer-to-array-of uint8_t[120000] 都会两者都解析到相同的地址(但类型截然不同)。

由于它们解析到相同的地址,并且由于 fread() 的第一个参数采用 void* 参数,因此错误不会被注意到。 (我只想说如果你尝试 fread (&Buffer4Can + 1, ... 事情不会顺利...)

@Domenic 指出的另一个问题是您对 fread() return 的比较。 fread() 的原型是:

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

其中 fread() 的 return 值为:

   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

在您的情况下,您为函数的 size 参数提供 sizeof(uint8_t),在您的情况下表示 return "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;
    }

(注意: fread() 的 return 类型是 size_t 因此需要强制转换 SizeofFile 以避免有符号和无符号值之间的比较)

当使用精确宽度类型时,用于输入和输出转换的宏在 inttypes.h 中提供(包括 stdint.h 本身) [=52= 的输出宏] 十六进制格式的值是 PRIx8。要每行输出 8 个 2-char 十六进制值并以 "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 */

(注意: PRIx8 宏不在 format-string 的引用部分内,它是独立的. 如果你想在最后换行,format-string 将是 " 0x%02" PRIx8 "\n")

有了它,您的程序应该可以按预期运行。请注意,它将要读取的文件名作为程序的第一个参数,或者如果提供了 none,它将默认从 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 */
}

(注意:所有多余的变量都被删除了,注意ftell()的return类型是long,不是int)

检查一下,如果您还有其他问题,请告诉我。

关于:

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

缓冲区 Buffer4Can 是一个数组名并引用一个 'bare' 数组名,退化为数组第一个字节的地址。因此,前置 & 是错误的。

参数也有问题:SizeofFile,因为函数需要类型为 size_t 的参数。建议:

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

fread()函数return读取'items'的数量。在当前语句中,每个项目的大小是 1,因此成功的读取操作将 return 第三个参数,因此而不是将 returned 值与 1 进行比较应该与 (size_t)SizeofFile

进行比较

来自 fread()

的手册页

成功时,fread() 和 fwrite() return 读取的项目数或 书面。此数字等于仅在以下情况下传输的字节数 size 为 1。如果发生错误,或者到达文件末尾,则 return 值为短项计数(或零)。

请注意 returned 类型和参数类型,并为函数提供它们所期望的。