I need to take in some input that is a string and turn it into its equal hex number and put it in place in a binary file.
char *fpath = argv[3];
FILE *f = fopen(fpath, "wb ");
char buf[1000];
char *input = "46AB";
unsigned int value = strtol(input , NULL, 16);
sprintf(buf, "\\x%x", value);
fseek(f, 2, SEEK_SET);
fputs(buf, f);
In the file it produces
5C 78 34 36 61
while i need it look like
46 AB
Is there an elegant way of doing this?
CodePudding user response:
Your sprintf
call created the string
\x46ab
and you wrote those six characters to the file without further interpretation, so that's what you saw in the file (hex bytes 5c 78 34 36 61 62
).
To avoid byte order issues, and to anticipate the possibility of an arbitrary-length input
string, you can do this one byte at a time with code like this:
char *p;
for(p = input; *p != '\0'; p = 2) {
unsigned int x;
if(sscanf(p, "%2x", &x) != 1) break;
putc(x, f);
}
This uses sscanf
to convert the input
string to hexadecimal, two characters (two hexadecimal digits, or one byte) at a time.
I also tested it after doing
input = "0102034a4b4c";
This is quick-and-dirty, imperfect code. It will misbehave if input
contains an odd number of characters, and it doesn't deal particularly gracefully with non-hexadecimal characters, either.
An improvement is to use the mildly obscure %n
format specifier to scanf
to discover exactly how many characters it consumed:
for(p = input; *p != '\0'; ) {
unsigned int x;
int n;
if(sscanf(p, "%2x%n", &x, &n) != 1) break;
putc(x, f);
p = n;
}
This should be more robust against malformed input
strings, although I have not tested it exhaustively. (I hardly ever use functions in the scanf family, let alone the more obscure format specifiers like %n
, but this is one of the few problems I know of where it's attractive, the alternatives being considerably more cumbersome.)
P.S. I got rid of your fseek
call, because I wasn't sure what it was there for and it confused my testing. You can put it back in if you need it.