Bagaimana cara membuang file biner sebagai string literal C / C ++?


39

Saya memiliki file biner yang ingin saya sertakan dalam kode sumber C saya (untuk sementara waktu, untuk tujuan pengujian) jadi saya ingin mendapatkan konten file sebagai string C, sesuatu seperti ini:

\x01\x02\x03\x04

Apakah ini mungkin, mungkin dengan menggunakan odatau hexdumputilitas? Meskipun tidak perlu, jika string dapat membungkus ke baris berikutnya setiap 16 byte input, dan termasuk tanda kutip ganda pada awal dan akhir setiap baris, itu akan lebih baik!

Saya sadar bahwa string akan memiliki nulls tertanam ( \x00) jadi saya perlu menentukan panjang string dalam kode, untuk mencegah byte ini mengakhiri string lebih awal.



Saya ingin yang serupa tetapi tetap menggunakan mesin terbang yang dapat dicetak ascii, hanya lolos dari 1-127, kutipan, garis miring terbalik, nol, dll.
把 友情 留 在 无 无 at

Jawaban:


10

Anda hampir dapat melakukan apa yang Anda inginkan hexdump, tetapi saya tidak tahu bagaimana cara mendapatkan tanda kutip & backslash tunggal ke dalam format string. Jadi saya melakukan sedikit post-processing dengan sed. Sebagai bonus, saya juga membuat indentasi setiap baris dengan 4 spasi. :)

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

Edit

Seperti yang ditunjukkan Cengiz Can, baris perintah di atas tidak sesuai dengan jalur data pendek. Jadi, inilah versi baru yang ditingkatkan:

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

Seperti yang disebutkan Malvineous dalam komentar, kita juga perlu memberikan -vopsi verbose hexdumpuntuk mencegahnya menyingkat byte yang identik *.

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

Ini menghasilkan elemen yang redundan dan tidak valid jika inputnya lebih pendek dari 16 byte.
Cengiz Can

@CengizCan:: oops :! Apakah itu lebih baik?
PM 2Ring

1
Perlu menambahkan -vopsi ke hexdump, jika tidak berjalan lama dari byte input yang sama menyebabkan jalur output yang mengatakan "*".
Malvineous

@Malvineous Poin bagus! Saya telah mengubah jawaban saya. Terima kasih atas bantuannya (dan terima kasih telah menerima jawaban saya).
PM 2Ring

66

xxdmemiliki mode untuk ini. The -i/ --includeoption akan:

output dalam C termasuk gaya file. Definisi array statis lengkap ditulis (dinamai file input), kecuali xxd membaca dari stdin.

Anda dapat membuangnya ke file menjadi #included, dan kemudian hanya mengakses fooseperti array karakter lain (atau menautkannya ke dalam). Ini juga termasuk deklarasi panjang array.

Outputnya dibungkus menjadi 80 byte dan pada dasarnya terlihat seperti apa yang Anda tulis dengan tangan:

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

xxdagak aneh adalah bagian dari vimdistribusi, jadi Anda mungkin sudah memilikinya. Jika tidak, di situlah Anda mendapatkannya - Anda juga dapat membuat alat sendiri dari vimsumbernya.


Bagus! Saya bahkan tidak tahu saya punya xxd. Sekarang saya hanya perlu mengingatnya ada waktu berikutnya saya membutuhkannya ... atau saya mungkin hanya akan meniru fungsi yang diperlukan dalam Python. :)
PM 2Ring

objcopyakan lebih baik
Lightness Races with Monica

@LightnessRacesinOrbit objcopyakan memungkinkan OP untuk menautkan data biner dengan file yang dapat dieksekusi, yang berguna tetapi tidak persis apa yang diminta di sini.
Mengembara Nauta

1
@WanderNauta: Anda akan mengaksesnya dengan cara yang hampir sama dengan yang Anda akses foo/ di foo_lensini, dan Anda tidak akan membuang-buang ruang penyimpanan. Saya yakin bahwa OP akan lebih baik objcopydan cocok dengan kebutuhannya.
Lightness Races with Monica

2
objcopybaik-baik saja ketika itu ada, tetapi tidak portabel dan hasilnya bahkan lebih sedikit. Ini tentu bisa menjadi bagian dari solusi permanen yang baik, tetapi itu bukan pertanyaan di sini.
Michael Homer

3

xxd bagus tetapi hasilnya sangat verbose dan membutuhkan banyak ruang penyimpanan.

Anda dapat mencapai hal yang sama dengan menggunakan praktis objcopy; misalnya

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

Kemudian tautkan foo.oke program Anda dan cukup gunakan simbol berikut:

00000550 D _binary_foo_end
00000550 A _binary_foo_size 
00000000 D _binary_foo_start

Ini bukan string literal, tetapi pada dasarnya sama dengan string literal berubah menjadi selama kompilasi (menganggap bahwa string literal sebenarnya tidak ada pada saat run-time; memang, tidak ada jawaban lain yang benar-benar memberi Anda string literal bahkan pada saat kompilasi) dan dapat diakses dengan cara yang hampir sama:

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

Kelemahannya adalah Anda perlu menentukan arsitektur target Anda untuk membuat file objek yang kompatibel, dan ini mungkin tidak sepele dalam sistem build Anda.


2

Seharusnya persis seperti yang Anda minta:

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

0

Ini adalah utilitas singkat yang saya tulis yang pada dasarnya melakukan hal yang sama (awalnya diposting di 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
Jawaban Anda akan lebih bermanfaat jika Anda juga memberikan contoh input dan output.
not2qubit

0

Jika Anda menggunakan python, muat ke dalam variabel "buff" dan gunakan sesuatu seperti ini:

buff2 = buff.encode("hex")
print ("0x"+", 0x".join([buff2[i:i+2] for i in range(0,len(buff2),2)]))
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.