Як скинути двійковий файл у вигляді літерального рядка C / C ++?


39

У мене є двійковий файл, який я хотів би включити у свій вихідний код C (тимчасово, для тестування), тому я хотів би отримати вміст файлу у вигляді рядка C, приблизно так:

\x01\x02\x03\x04

Чи можливо це, можливо , за допомогою odабо hexdumpутиліти? Хоча це і не потрібно, якщо рядок може переходити на наступний рядок кожні 16 вхідних байтів і включати подвійні лапки на початку та в кінці кожного рядка, це було б навіть приємніше!

Я знаю, що в рядок будуть вбудовані нулі ( \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 байт.
Cengiz Може

@CengizCan:: oops :! Це краще?
PM 2Ring

1
Потрібно додати -vопцію до hexdump, інакше довгі пробіги одного і того ж вхідного байта викликають вихідні рядки, які говорять "*".
Malvineous

@Malvineous Добрий момент! Я змінив свою відповідь. Дякую за голову (і дякую, що прийняли мою відповідь).
PM 2Ring

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було б краще
Гонки легкості з Монікою

@LightnessRacesinOrbit objcopyдозволить OP пов'язати бінарні дані з виконуваним файлом у вигляді об'єктного файлу, що корисно, але не точно, що тут задають.
Блукати Наута

1
@WanderNauta: Ви отримуватимете доступ до нього приблизно так само, як і ви foo/ foo_lenтут, і ви не витрачаєте багато місця на зберігання. Я переконаний, що в рамках ОП буде краще objcopyі що це відповідає його вимогам.
Легкі перегони з Монікою

2
objcopyчудово, коли він знаходиться навколо, але він не портативний, а вихід ще менше. Це, безумовно, може бути частиною хорошого постійного рішення, але тут не в цьому питання.
Майкл Гомер

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

Мінус полягає в тому, що вам потрібно вказати вашу цільову архітектуру, щоб зробити об’єктний файл сумісним, і це може не бути тривіально у вашій системі складання.



0

Це коротка утиліта, яку я написав, що по суті робить те ж саме (спочатку розміщено на переповнюванні стека ):

#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)]))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.