繁体   English   中英

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

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

我的 fread function 遇到了一些问题。 一切都很好,但我的错误检查器在 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
 }

您有许多细微的错误,然后正在检查fread的返回值是否不正确。 在您对fread的调用中,不需要在Buffer4Can之前加上&的地址)运算符。 Buffer4Can是一个数组,将在访问时转换为指向第一个元素的指针(请参阅: C11 标准 - 6.3.2.1 其他操作数 - 左值、arrays 和 function 指示符(p3)

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

由于它们解析到相同的地址,并且由于fread()void*参数作为其第一个参数,因此错误会默默地被忽视。 (如果您尝试fread (&Buffer4Can + 1, ...事情不会顺利...)

@Domenic 指出的另一个问题是您对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

在您的情况下,您为 function 的size参数提供sizeof(uint8_t) ,这意味着在您的情况下返回"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()的返回类型是size_t ,因此需要转换SizeofFile以避免有符号和无符号值之间的比较)

使用精确宽度类型时,用于输入和 output 转换的宏在inttypes.h中提供(包括stdint.h本身) 十六进制格式的unit8_t值的 output 的宏是PRIx8 对于 output 8 个 2-char hex-values 每行以"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宏不在格式字符串的引用部分内,它是独立的。如果您想要在末尾换行,格式字符串将是" 0x%02" PRIx8 "\n"

有了这个,您应该根据需要编程 function。 请注意,它将文件名作为程序的第一个参数读取,或者如果没有提供,则默认情况下将从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()的返回类型是long ,而不是int

如果您还有其他问题,请仔细查看并告诉我。

关于:

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

缓冲区Buffer4Can是一个数组名称,它引用了一个降级为数组第一个字节地址的“裸”数组名称。 因此,在前面加上&是一个错误。

参数也有问题: SizeofFile因为 function 需要一个size_t类型的参数。 建议:

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

fread() function 返回读取的“项目”数。 在当前语句中,每一项的大小都是1 ,所以一个成功的读取操作会返回第三个参数,所以应该比较(size_t)SizeofFile而不是将返回的值与1进行比较

fread()的 MAN 页面

成功时, fread() 和 fwrite() 返回读取或写入的项目数。 此数字等于仅当 size 为 1 时传输的字节数。如果发生错误或到达文件末尾,则返回值是一个短项计数(或零)。

请注意返回的类型和参数类型,并给函数他们所期望的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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