我想将一个二进制文件包含在我的 C 源代码中(暂时用于测试目的),因此我想以 C 字符串形式获取文件内容,如下所示:
\x01\x02\x03\x04
这可能吗,也许通过使用od
或hexdump
实用程序?虽然不是必需的,但如果字符串可以每 16 个输入字节换行到下一行,并在每行的开头和结尾包含双引号,那就更好了!
我知道该字符串将嵌入空值 ( \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 在评论中提到的,我们还需要将-v
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;
}