Bir ikili dosyayı C / C ++ string değişmez olarak nasıl atabilirim?


39

C kaynak koduma dahil etmek istediğim (geçici olarak test amaçlı) bir ikili dosyam var, böylece dosya içeriğini C dizesi olarak elde etmek istiyorum, bunun gibi bir şey:

\x01\x02\x03\x04

Bu, belki odveya hexdumpyardımcı programları kullanarak mümkün mü ? Zorunlu olmamakla birlikte, dize her 16 giriş baytında bir sonraki satıra sarabilir ve her satırın başında ve sonunda çift tırnak içerebilir, bu daha iyi olur!

Dize gömülmüş nulls ( \x00) olacağının farkındayım, bu nedenle bu baytların dizeyi erken sonlandırmasını önlemek için koddaki dizenin uzunluğunu belirtmem gerekecek.



Ben benzer istiyorum ama ascii yazdırılabilir glif, sadece 1-127 kaçış, alıntı, ters eğik çizgi, null, vb
koru

Yanıtlar:


10

İstediğiniz şeyi neredeyse yapabilirsiniz hexdump, ancak biçim dizesine tek tırnakların ve tırnakların nasıl alınacağını çözemiyorum. Bu yüzden biraz işlem sonrası yapıyorum sed. Bir bonus olarak, ayrıca her satırı 4 boşlukla girintiye çektim. :)

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

Düzenle

Cengiz Can'ın da belirttiği gibi, yukarıdaki komut satırı kısa veri hatları ile iyi başa çıkamaz. İşte yeni geliştirilmiş bir versiyon:

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

Malvineous'un yorumlarda belirttiği gibi, uzun özdeş baytları kısaltmasını önlemek için -vayrıntılı seçeneği de geçmemiz gerekiyor .hexdump*

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

Bu, giriş 16 bayttan daha kısa ise gereksiz ve geçersiz elemanlar üretir.
Cengiz,

@CengizCan:: oops :! Bu daha iyi mi?
PM 2Ring

1
-vSeçeneği eklemeniz gerekir hexdump, aksi takdirde aynı giriş baytının uzun çalıştırmaları söylenen çıkış hatlarına neden olur "*".
Malvineous

@Malvineous İyi nokta! Cevabımı değiştirdim. Yardımların için teşekkürler (ve cevabımı kabul ettiğin için teşekkürler).
PM 2Ring

66

xxdBunun için bir modu var. -i/ --includeSeçenek olacak:

C çıktısı dosya stilini içerir. Xxd stdin'den okumadığı sürece, tam bir statik dizi tanımı (giriş dosyasından sonra adlandırılmış) yazılır.

Bu dosyayı #included olması için bir dosyaya bırakabilir ve sonra foodiğer karakter dizileri gibi erişebilirsiniz (ya da içine bağlayabilirsiniz). Ayrıca, dizinin uzunluğunun bir bildirimini de içerir.

Çıktı 80 bayta sarılır ve el ile yazabilecekleriniz gibi görünür:

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

xxdbiraz garip bir şekilde, vimdağıtımın bir parçası , bu yüzden muhtemelen zaten var. Olmazsa, onu aldığınız yer orasıdır - aracı vimkaynaktan kendi başına da oluşturabilirsiniz .


Güzel! Xxd olduğunu bile bilmiyordum. Şimdi bir dahaki sefere ihtiyacım olduğunda var olduğunu hatırlamak zorundayım ... ya da muhtemelen Python'da gerekli işlevselliği çoğaltacağım. :)
PM 2Ring

objcopydaha iyi olurdu
Hafiflik Yarışları Monica ile

@LightnessRacesinOrbit objcopy, OP'nin ikili verileri yürütülebilir dosyayla çalıştırılabilir dosyaya bağlamasına olanak tanır, bu faydalı ancak tam olarak burada sorulanı değil.
Wander Nauta,

1
@WanderNauta: Buraya, erişeceğiniz foo/ erişeceğiniz şekilde hemen hemen erişir ve depolama alanını büyük ölçüde boşa harcamazsınız . OP’nin daha iyi olacağına ve onun gereksinimlerine uygun olduğuna ikna oldum . foo_lenobjcopy
Monica ile

2
objcopyetrafında olduğunda iyidir, ancak taşınabilir değil ve çıktı daha az. Kesinlikle iyi bir kalıcı çözümün parçası olabilir, ancak buradaki sorun bu değil.
Michael Homer

3

xxd iyidir ancak sonuç oldukça ayrıntılıdır ve çok fazla depolama alanı gerektirir.

Neredeyse aynı şeyi kullanarak elde edebilirsiniz objcopy; Örneğin

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

Ardından foo.oprogramınıza bağlanın ve aşağıdaki simgeleri kullanın:

00000550 D _binary_foo_end
00000550 A _binary_foo_size 
00000000 D _binary_foo_start

Bu bir dize değişmezi değildir, ancak derleme sırasında bir dize değişmezinin dönüştüğü ile aynı şeydir (dize değişmezlerinin gerçekte çalışma zamanında bulunmadığını düşünün ; gerçekte, diğer cevapların hiçbiri gerçekte değişmez derleme zamanında bile) ve büyük ölçüde aynı şekilde erişilebilir:

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

Dezavantajı, nesne dosyasını uyumlu hale getirmek için hedef mimarinizi belirtmeniz gerekmesidir ve bu, derleme sisteminizde önemsiz olmayabilir.


2

Tam olarak istediğin gibi olmalı:

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

0

Bu yazdığım kısa bir yardımcı programdır, aslında aynı şeyi yapar (başlangıçta Stack Overflow'ta yayınlanmıştır ):

#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
Bununla birlikte giriş ve çıkış örneklerini de sağladıysanız cevabınız daha yararlı olacaktır.
not2qubit 7:15

0

Eğer python iseniz, onu "buff" değişkenine yükleyin ve şunun gibi bir şey kullanın:

buff2 = buff.encode("hex")
print ("0x"+", 0x".join([buff2[i:i+2] for i in range(0,len(buff2),2)]))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.