55

I have a binary file I would like to include in my C source code (temporarily, for testing purposes) so I would like to obtain the file contents as a C string, something like this:

\x01\x02\x03\x04

Is this possible, perhaps by using the od or hexdump utilities? While not necessary, if the string can wrap to the next line every 16 input bytes, and include double-quotes at the start and end of each line, that would be even nicer!

I am aware that the string will have embedded nulls (\x00) so I will need to specify the length of the string in the code, to prevent these bytes from terminating the string early.

2

6 Answers 6

85

xxd has a mode for this. The -i/--include option will:

output in C include file style. A complete static array definition is written (named after the input file), unless xxd reads from stdin.

You can dump that into a file to be #included, and then just access foo like any other character array (or link it in). It also includes a declaration of the length of the array.

The output is wrapped to 80 bytes and looks essentially like what you might write by hand:

$ xxd --include foo
unsigned char foo[] = {
  0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64,
  0x21, 0x0a, 0x0a, 0x59, 0x6f, 0x75, 0x27, 0x72, 0x65, 0x20, 0x76, 0x65,
  0x72, 0x79, 0x20, 0x63, 0x75, 0x72, 0x69, 0x6f, 0x75, 0x73, 0x21, 0x20,
  0x57, 0x65, 0x6c, 0x6c, 0x20, 0x64, 0x6f, 0x6e, 0x65, 0x2e, 0x0a
};
unsigned int foo_len = 47;

xxd is, somewhat oddly, part of the vim distribution, so you likely have it already. If not, that's where you get it — you can also build the tool on its own out of the vim source.

6
  • Nice! I didn't even know I had xxd. Now I just have to remember it exists next time I need it... or I'll probably just replicate the required functionality in Python. :)
    – PM 2Ring
    Commented Dec 27, 2014 at 7:01
  • objcopy would be better Commented Dec 28, 2014 at 0:55
  • @LightnessRacesinOrbit objcopy would allow OP to link the binary data with the executable as an object file, which is useful but not exactly what's being asked here. Commented Dec 28, 2014 at 13:38
  • 1
    @WanderNauta: You would access it in pretty much the same way as you'd access foo/foo_len here, and you wouldn't be vastly wasting storage space. I am convinced that the OP would be better off with objcopy and that it suits his or her requirements. Commented Dec 28, 2014 at 13:49
  • 3
    objcopy is fine when it's around, but it's not portable and the output even less so. It can certainly be part of a good permanent solution, but that isn't the question here. Commented Dec 28, 2014 at 18:15
14

You can almost do what you want with hexdump, but I can't figure out how to get quotes & single backslashes into the format string. So I do a little post-processing with sed. As a bonus, I've also indented each line by 4 spaces. :)

hexdump -e '16/1 "_x%02X" "\n"' filename | sed 's/_/\\/g; s/.*/    "&"/'

Edit

As Cengiz Can pointed out, the above command line doesn't cope well with short data lines. So here's a new improved version:

hexdump -e '16/1 "_x%02X" "\n"' filename | sed 's/_/\\/g; s/\\x  //g; s/.*/    "&"/'

As Malvineous mentions in the comments, we also need to pass the -v verbose option to hexdump to prevent it from abbreviating long runs of identical bytes to *.

hexdump -v -e '16/1 "_x%02X" "\n"' filename | sed 's/_/\\/g; s/\\x  //g; s/.*/    "&"/'
4
  • This produces redundant and invalid elements if input is shorter than 16 bytes.
    – Cengiz Can
    Commented Dec 27, 2014 at 10:03
  • @CengizCan: :oops:! Is that better?
    – PM 2Ring
    Commented Dec 27, 2014 at 10:38
  • 1
    Need to add the -v option to hexdump, otherwise long runs of the same input byte cause output lines that say "*".
    – Malvineous
    Commented Dec 21, 2016 at 3:45
  • @Malvineous Good point! I've amended my answer. Thanks for the heads-up (and thanks for accepting my answer).
    – PM 2Ring
    Commented Dec 21, 2016 at 5:21
6

xxd is good but the result is highly verbose and takes a lot of storage space.

You can achieve practically the same thing using objcopy; e.g.

objcopy --input binary \
    --output elf32-i386 \
    --binary-architecture i386 foo foo.o

Then link foo.o to your program and simply use the following symbols:

00000550 D _binary_foo_end
00000550 A _binary_foo_size 
00000000 D _binary_foo_start

This is not a string literal, but it's essentially the same thing as what a string literal turns into during compilation (consider that string literals do not in fact exist at run-time; indeed, none of the other answers actually give you a string literal even at compile-time) and can be accessed in largely the same way:

unsigned char* ptr = _binary_foo_start;
int i;
for (i = 0; i < _binary_foo_size; i++, ptr++)
   putc(*ptr);

The downside is that you need to specify your target architecture to make the object file compatible, and this may not be trivial in your build system.

4

Should be exactly what you asked for:

hexdump -v -e '"\\" "x" 1/1 "%02X"' file.bin ; echo
1
  • This is the best answer so far, imo.
    – Droopycom
    Commented Feb 10 at 4:57
0

This is a short utility I wrote that essentially does the same thing (originally posted on Stack Overflow):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LENGTH 80

int main(void)
{
    FILE *fout = fopen("out.txt", "w");

    if(ferror(fout))
    {
        fprintf(stderr, "Error opening output file");
        return 1;
    }
    char init_line[]  = {"char hex_array[] = { "};
    const int offset_length = strlen(init_line);

    char offset_spc[offset_length];

    unsigned char buff[1024];
    char curr_out[64];

    int count, i;
    int line_length = 0;

    memset((void*)offset_spc, (char)32, sizeof(char) * offset_length - 1);
    offset_spc[offset_length - 1] = '\0';

    fprintf(fout, "%s", init_line);

    while(!feof(stdin))
    {
        count = fread(buff, sizeof(char), sizeof(buff) / sizeof(char), stdin);

        for(i = 0; i < count; i++)
        {
            line_length += sprintf(curr_out, "%#x, ", buff[i]);

            fprintf(fout, "%s", curr_out);
            if(line_length >= MAX_LENGTH - offset_length)
            {
                fprintf(fout, "\n%s", offset_spc);
                line_length = 0;
            }
        }
    }
    fseek(fout, -2, SEEK_CUR);
    fprintf(fout, " };");

    fclose(fout);

    return EXIT_SUCCESS;
}
1
  • 1
    Your answer would be more useful if you also provided the input and output examples with it.
    – not2qubit
    Commented Mar 7, 2015 at 13:43
0

If you are into python, load it into a variable "buff" and use something like this:

buff2 = buff.encode("hex")
print ("0x"+", 0x".join([buff2[i:i+2] for i in range(0,len(buff2),2)]))

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .