내 C 소스 코드에 (일시적으로 테스트 목적으로) 바이너리 파일을 포함하고 싶기 때문에 파일 내용을 다음과 같은 C 문자열로 가져오고 싶습니다.
\x01\x02\x03\x04
od
또는 유틸리티를 사용하여 이것이 가능합니까 hexdump
? 필수는 아니지만 문자열이 16개의 입력 바이트마다 다음 줄로 줄 바꿈되고 각 줄의 시작과 끝에 큰따옴표를 포함할 수 있다면 좋을 것입니다!
문자열에 null 값이 포함( \x00
)된다는 것을 알고 있으므로 이러한 바이트로 인해 문자열이 조기에 종료되는 것을 방지하려면 코드에서 문자열 길이를 지정해야 합니다.
답변1
xxd
이를 수행하는 패턴이 있습니다. -i
/옵션은 --include
다음을 수행합니다.
C의 출력에는 파일 스타일이 포함되어 있습니다. xxd가 stdin에서 읽지 않는 한 완전한 정적 배열 정의(입력 파일 이름을 따서 명명됨)를 작성합니다.
다른 문자 배열처럼 쓰기 위해 파일에 덤프한 #include
다음 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
.
답변2
당신은 할 수거의원하는 대로 작동 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가 주석에서 언급했듯이, 동일한 bytes의 장기 실행을 단축하는 것을 방지 -v
하려면 verbose 옵션을 verbose에 전달 해야 합니다 .hexdump
*
hexdump -v -e '16/1 "_x%02X" "\n"' filename | sed 's/_/\\/g; s/\\x //g; s/.*/ "&"/'
답변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);
단점은 대상 파일을 호환 가능하게 만들기 위해 대상 아키텍처를 지정해야 한다는 것인데, 이는 빌드 시스템에서는 중요하지 않을 수 있습니다.
답변4
다음은 본질적으로 동일한 작업을 수행하는 짧은 유틸리티입니다(원래 게시됨).스택 오버플로):
#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;
}