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


39

Cソースコードに(一時的にテスト目的で)含めたいバイナリファイルがあるので、ファイルの内容を次のようなC文字列として取得したいと思います。

\x01\x02\x03\x04

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

文字列にnull(\x00)が埋め込まれることを認識しているため、これらのバイトが文字列を早期に終了させないように、コード内で文字列の長さを指定する必要があります。



私は類似したいが、ASCII印刷可能なグリフのみ1-127を脱出、引用符、バックスラッシュ、ヌルなどを保持
把友情留在无盐

回答:


10

あなたはできるほとんどあなたがやりたい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冗長なオプションを渡してhexdump、同一のバイトの長い実行をに短縮しないようにする必要もあります*

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

入力が16バイトより短い場合、これにより冗長で無効な要素が生成されます。
センギスは14

@CengizCan::oops :! それは良いですか?
PM 2リング14

1
-vオプションを追加する必要がありますhexdump。そうしないと、同じ入力バイトが長時間実行されると、出力行に"*"
Malvineous 16

@Malvineous良い点!答えを修正しました。ヘッズアップに感謝します(そして私の答えを受け入れてくれてありがとう)。
PM 2Ring 16

66

xxdこのためのモードがあります。-i/ --includeオプションは以下となります。

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

それをファイルにダンプして#includedにし、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。ソースからツールを独自に構築することもできます。


いいね!xxdがあることすら知りませんでした。今、私はそれが次に必要なときに存在することを覚えておく必要があります...または、おそらくPythonで必要な機能を複製するだけでしょう。:)
PM 2Ring

objcopyより良いだろう
モニカと明度レース14

@LightnessRacesinOrbit objcopyを使用すると、OPはバイナリデータをオブジェクトファイルとして実行可能ファイルにリンクできます。これは便利ですが、ここで何が要求されているかは正確ではありません。
ワンダナウタ14

1
@WanderNauta:あなたがアクセスいただきたいとほとんど同じ方法でそれにアクセスするfoo/ foo_lenここに、そしてあなたが大幅に収納スペースを無駄にすることはないだろう。OPの方が良いと確信しており、OPがobjcopy彼または彼女の要件に合っていると確信しています。
モニカとの明度レース

2
objcopy周りにあるときは問題ありませんが、ポータブルではなく、出力はさらに少なくなります。それは確かに永続的な解決策の一部になる可能性がありますが、それはここでの質問ではありません。
マイケルホーマー14

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);

欠点は、オブジェクトファイルの互換性を確保するためにターゲットアーキテクチャを指定する必要があることです。これは、ビルドシステムでは簡単ではない場合があります。


2

まさにあなたが求めたものでなければなりません:

hexdump -v -e '"\\" "x" 1/1 "%02X"' file.bin ; echo

0

これは私が書いた短いユーティリティで、基本的に同じことを行います(元々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
入力と出力の例も提供しておけば、答えはより便利です。
-not2qubit

0

Pythonを使用している場合は、変数「buff」にロードし、次のようなものを使用します。

buff2 = buff.encode("hex")
print ("0x"+", 0x".join([buff2[i:i+2] for i in range(0,len(buff2),2)]))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.