Home > database >  How to get a hex dump from a binary file into C
How to get a hex dump from a binary file into C

Time:06-23

I'm dabbling in a bit of Game Boy save state hacking, and I'm currently getting my head around reading from a binary file in C. I understand that char is one byte so I'm reading in chars using the following code

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

int main () {
   FILE *fp = NULL;
   char buffer[100];
   int filesize;

   fp = fopen("save file.srm", "r "); //open
   if(fp == NULL) printf("File loading error number %i\n", errno); 
   fseek(fp, 0L, SEEK_END); //seek to end to get file size
   filesize = ftell(fp);
   printf("Filesize is %i bytes\n",filesize);
   
   fseek(fp, 0, SEEK_SET); //set read point at start of file
   fread(buffer, sizeof buffer, 1, fp);//read into buffer
   
   for(int i=70;i<80;i  ) printf("%x\n", buffer[i]); //display
   
   fclose(fp);
   
   return(0);
}

The output I get is

Filesize is 32768 bytes
ffffff89
66
ffffff85
2
2
ffffff8b
44
ffffff83
c
0

I'm trying to load in bytes, so I want each row of the output to have maximum value 0xff. Can someone explain why I'm getting ffffff8b?

CodePudding user response:

if(fp == NULL) printf("File loading error number %i\n", errno);

When you detect an error, do not just print a message. Either exit the program or do something to correct for the error.

char buffer[10];

Use unsigned char for working with raw data. char may be signed, which can cause undesired effects.

fread(buffer, strlen(buffer) 1, 1, fp);

buffer has not been initialized at this point, so the behavior of strlen(buffer) is not defined by the C standard. In any case, you do not want to use the length of the string currently in buffer as the size for fread. You want the size of the array. So use sizeof buffer (without the 1).

for(int i=0;i<10;i )

Do not iterate to ten. Iterate to the number of bytes put into the buffer by fread. fread returns size_t value that is the number of items read. If you use it as size_t n = fread(buffer, 1, sizeof buffer, fp);, the number of items (in n) will be the number of bytes read, since having 1 for the second argument says each item to read is one byte.

printf("%x\n", buffer[i]);

To print an unsigned char, use %hhx. Because your buffer had signed char elements, some of them were negative. When used in this printf, they were promoted to negative int values. Then, because of the %x, printf attempted to print them as unsigned int values. All the extra bits from the negative values in two’s complement form showed up.

CodePudding user response:

Very simply: char can be signed or unsigned by default: that's down to the compiler. In your case, it appears to be signed.

When you pass the char of buffer[i] to printf(), it is promoted to int, and sign-extended if the original char value had its top bit set. Hence anything that's in the range 0x80-0xff gets a lot of fs prefixing the value.

If you declare buffer to be unsigned char, this problem should not occur. But you should, in combination with that, use "%hhx" rather than "%x" for your printf() format, since the hh length modifier forces printf() to mask the input value so that only those bits applicable to an unsigned char (given that you're using the x specifier) are used.

  • Related