我有一个二进制文件,希望将其包含在C源代码中(出于测试目的),因此我想以C字符串的形式获取文件内容,如下所示:
\x01\x02\x03\x04
是否可以使用od
或hexdump
实用程序?虽然不是必须的,但是如果字符串可以每16个输入字节换行到下一行,并且在每行的开头和结尾都包含双引号,那会更好!
我知道该字符串将具有嵌入的null(\x00
),因此我将需要在代码中指定该字符串的长度,以防止这些字节尽早终止该字符串。
我有一个二进制文件,希望将其包含在C源代码中(出于测试目的),因此我想以C字符串的形式获取文件内容,如下所示:
\x01\x02\x03\x04
是否可以使用od
或hexdump
实用程序?虽然不是必须的,但是如果字符串可以每16个输入字节换行到下一行,并且在每行的开头和结尾都包含双引号,那会更好!
我知道该字符串将具有嵌入的null(\x00
),因此我将需要在代码中指定该字符串的长度,以防止这些字节尽早终止该字符串。
Answers:
您几乎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
verbose选项,hexdump
以防止其将相同字节的长期运行缩写为*
。
hexdump -v -e '16/1 "_x%02X" "\n"' filename | sed 's/_/\\/g; s/\\x //g; s/.*/ "&"/'
-v
选项hexdump
,否则长时间运行相同的输入字节会导致输出行显示为"*"
。
xxd
有一个模式。在-i
/ --include
选项会:
C语言中的输出包括文件样式。写入完整的静态数组定义(以输入文件命名),除非xxd从stdin中读取。
您可以将其转储到文件#include
d中,然后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
源头上自行构建该工具。
objcopy
会更好
objcopy
将允许OP将二进制数据与可执行文件链接为目标文件,这很有用,但不完全是这里要问的内容。
foo
/ 几乎相同的方式来访问它foo_len
,并且不会浪费大量的存储空间。我坚信,OP会更好,objcopy
并且可以满足他或她的要求。
objcopy
可以使用,但它不是可移植的,输出甚至更少。它当然可以是一个好的永久解决方案的一部分,但这不是这里的问题。
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);
缺点是您需要指定目标体系结构以使目标文件兼容,这在您的构建系统中可能并不容易。
这是我写的一个简短实用程序,它实际上执行相同的操作(最初发布在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;
}