Reputation: 1
I can't seem to load a binary file into the memory for better read performance compared to the more expensive reads to the actual file. The file is 124 MB and should be able to fit entirely into memory. This is in C, compiled by GCC 6.3 on a 84_64 GNU/Linux.
Something goes wrong when trying to access blk*
from the fread
.
The two malloc calls that I tried are:
uint8_t *blk = malloc(sizeof(uint8_t) * fileSize + 1);
uint8_t *blk = (uint8_t *) malloc(sizeof(uint8_t) * fileSize + 1);
And checked to see if malloc
returned NULL but it didn't.
FILE *file = fopen("path", "rb");
fseek(file, 0, SEEK_END);
long fileSize = ftell(file);
if (ftell(file) != EOF) {
printf("Ftell not EOF);
}
fseek(file, 0, SEEK_SET);
uint8_t *blk = malloc(sizeof(uint8_t) * fileSize + 1);
if (file != NULL) {
printf("File Not NULL and %d\n", fileSize);
}
if (blk) {
printf("Not NULL\n");
} else {
printf("NULL\n");
}
fread(blk, 1, fileSize, file);
fclose(file);
printf("blk: %p | %d\n", *&blk, blk);
The output is:
Ftell not EOF
File Not NULL and 134215964
blk: 0x7fffffffdcc0 | -9024
Not NULL
Segmentation fault
Print format might be wrong but it shouldn't matter for a segmentation error.
Upvotes: 0
Views: 408
Reputation: 84642
If you haven't figured it out yet, your segmentation fault is cause by:
printf("blk: %p | %d\n", *&blk, blk);
Due to your attempt to print blk
(a pointer to uint8_t
) as an integer. A mismatch between argument types and the printf
format specifier invokes Undefined Behavior.
C11 Standard - 7.21.6.1 The fprintf function(p9)
" If a conversion specification is invalid, the behavior is undefined. If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined."
Note also, you use of '*&'
before blk
in that statement is superfluous. It is simply blk
. Dereferencing the address of a pointer is simply the pointer itself. You can correct your statement to print the pointer address and first byte in blk
by using the proper exact width macros from inttypes.h
, e.g.
printf("blk: %p | 0x%02" PRIx8 "\n", (void*)blk, *blk);
In your allocation, there is no need for fileSize + 1
, unless you expect to use a hack to affirmatively nul-terminate blk
so it can be used as a string. It can be convenient in some cases, but it's not generally recommended. When ftell
returns the number of bytes in the file, that's all you need to allocate for, unless you plan on adding something at the end. Further, sizeof(uint8_t)
like sizeof(char)
is always 1
- it too is superfluous, e,g,
if (!(blk = malloc (filesize))) { /* validate allocation */
perror ("malloc-blk");
return 1;
}
Further, WhozCraig was trying to convey to you that each step should be validated. With proper validation, there isn't any question where the code is failing. Adding validations to each step would look something similar to:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
int main (int argc, char **argv) {
uint8_t *blk;
long filesize;
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
if (fseek (fp, 0, SEEK_END) == -1) { /* validate seek end */
perror ("fseek-SEEK_END");
return 1;
}
if ((filesize = ftell (fp)) == -1) { /* validate ftell */
perror ("ftell-fp");
return 1;
}
if (fseek (fp, 0, SEEK_SET) == -1) { /* validate seek set */
perror ("fseek-SEEK_SET");
return 1;
}
if (!(blk = malloc (filesize))) { /* validate allocation */
perror ("malloc-blk");
return 1;
}
if (fread (blk, 1, filesize, fp) != (size_t)filesize) { /* validate read */
perror ("fread-blk");
return 1;
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
/* do what you need with blk here */
printf("blk: %p | 0x%02" PRIx8 "\n", (void*)blk, *blk);
free (blk);
}
(note: don't forget to free (blk);
when you are done with its use)
Example Use/Output
Running the code as-is against any file will simply output the pointer address for blk
and the first byte in the file in 2-digit hex, e.g.
$ ./bin/rdfileintoblk ../dat/captnjack.txt
blk: 0x17e9240 | 0x54
Look things over and let me know if you have any questions.
Upvotes: 2