在第一个 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.
在您的情况下,您为函数的 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 类型和参数类型,并为函数提供它们所期望的。
我的恐惧函数一直有问题。 一切都很好,但我的错误检查器在 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.
在您的情况下,您为函数的 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 类型和参数类型,并为函数提供它们所期望的。