0

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?

4
  • 2
    You'll want to use fwrite to write the data in value directly to the file. Commented Sep 28, 2021 at 3:55
  • 1
    snprintf and fputs are string/text operators. You cannot use that to produce binary data. All you need is fwrite(&value, sizeof(value), 1, f) Commented Sep 28, 2021 at 3:57
  • I believe both these comments are wrong for common little-endian machines. Commented Sep 28, 2021 at 4:20
  • If you want see the data as hex values you can check hex edit Commented Sep 28, 2021 at 4:22

1 Answer 1

1

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 get the hex-to-binary conversion you want, while avoiding byte order issues and anticipating 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 output byte) at a time.

I also tested it with a longer input string:

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 each time:

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.