Con imagemagick:
convert file.png data.h
Restituisce qualcosa come:
/*
data.h (PNM).
*/
static unsigned char
MagickImage[] =
{
0x50, 0x36, 0x0A, 0x23, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20,
0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4D, 0x50, 0x0A, 0x32, 0x37,
0x37, 0x20, 0x31, 0x36, 0x32, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
....
Per compatibilità con altro codice puoi quindi utilizzare fmemopen
per ottenere un FILE *
"normale". oggetto, o in alternativa std::stringstream
per creare un iostream
. std::stringstream
non è eccezionale per questo però e ovviamente puoi semplicemente usare un puntatore ovunque tu possa usare un iteratore.
Se lo stai usando con automake, non dimenticare di impostare BUILT_SOURCES in modo appropriato.
La cosa bella di farlo in questo modo è:
- Ottieni il testo, quindi può essere nel controllo della versione e patch in modo ragionevole
- È portatile e ben definito su ogni piattaforma
Puoi incorporare file binari nell'eseguibile usando ld
linker. Ad esempio, se hai il file foo.bar
quindi puoi incorporarlo nell'eseguibile aggiungendo i seguenti comandi a ld
--format=binary foo.bar --format=default
Se stai invocando ld
attraverso gcc
quindi dovrai aggiungere -Wl
-Wl,--format=binary -Wl,foo.bar -Wl,--format=default
Qui --format=binary
dice al linker che il seguente file è binario e --format=default
ritorna al formato di input predefinito (questo è utile se specifichi altri file di input dopo foo.bar
).
Quindi puoi accedere al contenuto del tuo file dal codice:
extern uint8_t data[] asm("_binary_foo_bar_start");
extern uint8_t data_end[] asm("_binary_foo_bar_end");
C'è anche un simbolo chiamato "_binary_foo_bar_size"
. Penso che sia di tipo uintptr_t
ma non l'ho controllato.
Aggiorna Ho imparato a preferire il controllo dell'assembly .incbin
di John Ripley offerte di soluzioni basate e ora utilizza una variante su questo.
Ho usato objcopy (GNU binutils) per collegare i dati binari da un file foo-data.bin nella sezione dati dell'eseguibile:
objcopy -B i386 -I binary -O elf32-i386 foo-data.bin foo-data.o
Questo ti dà un foo-data.o
oggetto che puoi collegare al tuo eseguibile. L'interfaccia C è simile a
/** created from binary via objcopy */
extern uint8_t foo_data[] asm("_binary_foo_data_bin_start");
extern uint8_t foo_data_size[] asm("_binary_foo_data_bin_size");
extern uint8_t foo_data_end[] asm("_binary_foo_data_bin_end");
quindi puoi fare cose come
for (uint8_t *byte=foo_data; byte<foo_data_end; ++byte) {
transmit_single_byte(*byte);
}
o
size_t foo_size = (size_t)((void *)foo_data_size);
void *foo_copy = malloc(foo_size);
assert(foo_copy);
memcpy(foo_copy, foo_data, foo_size);
Se la tua architettura di destinazione ha vincoli speciali su dove vengono archiviati i dati costanti e variabili o desideri archiviare tali dati nel .text
segmento per farlo rientrare nello stesso tipo di memoria del codice del programma, puoi giocare con il objcopy
altri parametri.