バイナリファイルをC / C ++文字列リテラルにダンプする方法は?

バイナリファイルをC / C ++文字列リテラルにダンプする方法は?

私のCソースコードに(一時的にテスト目的で)バイナリファイルを含めたいので、ファイルの内容を次のC文字列にインポートしたいと思います。

\x01\x02\x03\x04

odまたはユーティリティを使用してこれは可能ですかhexdump?必須ではありませんが、文字列が16個の入力バイトごとに次の行に折り返され、各行の先頭と末尾に二重引用符を含めることができると思います。

文字列にNULL値が含まれて\x00いることがわかっているため、これらのバイトが文字列を早期に終了しないようにするには、コードで文字列の長さを指定する必要があります。

答え1

xxdこれを行うパターンがあります。-i/オプションは--include次のことを行います。

Cの出力にはファイルスタイルが含まれています。 xxdがstdinから読み取らない限り、完全な静的配列定義(入力ファイル名にちなんで命名)を作成します。

他の文字配列と同様に、書き込み用にファイルにダンプしてから#includeアクセスfoo(またはリンク)できます。また、配列長宣言も含まれます。

出力は80バイトに圧縮され、デフォルトで直接作成したものと同じです。

$ 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やや奇妙なことに、これはvimディストリビューションの一部なので、すでに持っているでしょう。そうでなければそこから得ることができます。ソースから直接ツールをビルドすることもできますvim

答え2

あなたはできますほぼ好きなように動作しますhexdumpが、フォーマット文字列に引用符と単一のバックスラッシュを入れる方法がわかりません。だからsed。ボーナスで各行を4マスずつインデントします。 :)

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

編集する

Cengiz Canが指摘したように、上記のコマンドラインは短いデータ行をうまく処理できません。新しく改良されたバージョンは次のとおりです。

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

Malvineousがコメントで述べたように、同じバイトの長期実行を短縮するのを防ぐ-vために、verboseオプションをverboseに渡す必要があります。hexdump*

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

答え3

xxd大丈夫ですが、結果はあまりにも冗長で、多くのストレージスペースを占めています。

以下を使用すると、ほぼ同じ結果が得られます。objcopy;例えば

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

foo.o次にプログラムに接続し、次の記号を使用します。

00000550 D _binary_foo_end
00000550 A _binary_foo_size 
00000000 D _binary_foo_start

これは文字列リテラルではありませんが、本質的にコンパイル中に文字列リテラルになるのと同じです(文字列を考慮してください)。言葉実際、ランタイムには存在しません。実際、コンパイル時にも他の答えのどれも実際に文字列リテラルを提供せず、ほぼ同じ方法でアクセスできます。

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

欠点は、ターゲットファイルを互換性にするためにターゲットアーキテクチャを指定する必要があることです。これはビルドシステムにとって重要ではない可能性があります。

答え4

以下は、基本的に同じことを行う短いユーティリティです(元々公開)。スタックオーバーフロー):

#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;
}

関連情報