【问题标题】:C++: How to add raw binary data into source with Visual Studio?C++:如何使用 Visual Studio 将原始二进制数据添加到源代码中?
【发布时间】:2011-08-08 18:06:55
【问题描述】:

我有一个二进制文件,我想直接嵌入到我的源代码中,所以它会直接编译成 .exe 文件,而不是从文件中读取它,所以当我执行的时候数据已经在内存中了启动程序。

我该怎么做?

我得到的唯一想法是将二进制数据编码为 base64,将其放入字符串变量中,然后将其解码回原始二进制数据,但这是一种棘手的方法,会导致毫无意义的内存分配。另外,我想将数据存储在 .exe 中,与原始数据一样紧凑。

编辑:我想到使用base64的原因是因为我也想让源代码文件尽可能小。

【问题讨论】:

  • 只要你把这个资源放在一个单独的源文件中,我认为没有理由让源大小成为关注的一部分。让它易于使用并且首先要清楚发生了什么,让编译器担心读取一些额外的字符。
  • 这只是我的喜好,当然没关系,但我喜欢紧凑型。
  • 既然你喜欢compact:stackoverflow.com/a/52843063/6846474我写了一个工具,它可以将带有资源路径列表的头文件直接编译成目标文件或静态库。

标签: c++ visual-studio-2008 binary-data


【解决方案1】:

最简单和最便携的方法是编写一个小的 将数据转换为 C++ 源代码的程序,然后编译 并将其链接到您的程序中。这个生成的文件可能 看起来像:

unsigned char rawData[] =
{
    0x12, 0x34, // ...
};

【讨论】:

  • 对于不支持文件操作的系统上的固件更新,我不得不这样做,我们只是将原始数据复制到数组中,如本答案所示。
  • 在我的源代码中执行此操作的最紧凑方式是什么?我可以通过不使用 0x 前缀和使用十进制值来优化空间,但是还有其他方法吗?我看过类似的代码:Y\377\322\217^\377\321\227l\377\340\262\220\377,但我不明白它是如何工作的,并且由于某种原因它会导致一些编译器警告,但是它可以工作。
  • @Rookie:\nnn 表示法使用八进制来指定每个字符的值。 \377 与 0xff 相同。
  • 是的,但是这些奇怪的字母在八进制数据中有什么作用?例如有Y^l 等,那里有很多奇怪的字符,我不明白其中的逻辑。
  • @Rookie 据推测,并非所有字符都是八进制转义符。就个人而言,我不会太担心源代码文件的大小;如果遇到大小问题,那是因为总表对于编译器来说太大了,这将是在标记化之后,并且不会依赖于输入文件的大小。
【解决方案2】:

有这方面的工具,一个典型的名字是“bin2c”。第一个搜索结果是this page

您需要创建一个char 数组,最好也创建一个static const

在 C 中:

可能需要注意一下,因为您不能有 char 类型的文字,而且通常 C 的 char 数据类型的签名取决于实现。

您可能希望使用诸如

之类的格式
static const unsigned char my_data[] = { (unsigned char) 0xfeu, (unsigned char) 0xabu, /* ... */ };

请注意,每个 unsigned int 文字都被强制转换为 unsigned char,还有使它们无符号的 'u' 后缀。

由于这个问题是针对 C++ 的,您可以有一个 char 类型的文字,您可以考虑使用这样的格式,而不是:

static const char my_data[] = { '\xfe', '\xab', /* ... */ };

因为这只是一个字符数组,你也可以使用普通的字符串文字语法。嵌入零字节应该没问题,只要您不尝试将其视为字符串:

static const char my_data[] = "\xfe\xdab ...";

这是最紧凑的解决方案。事实上,你也可以将它用于 C。

【讨论】:

  • \xff 等于 0xff ?等于 255,当使用逗号时,它的大小相同,但十进制也可以是 0,0,0,0 或 11,11,11,11,因此在某些情况下它会小 1 到 2 个字节,而十六进制始终为 4 个字节。我想我用小数,如果这些都是这里的选项?
  • 你能否解释一下这个数据Y\377\322\217^\377\321\227l\377\340\262\220\377,你在八进制值中看到Y^l,它们的逻辑是什么?
  • 避免像 0 这样的字面量的重点是(对我而言)是类型干净的; 1 的类型是int。我猜编译器通常会在初始化时进行边界检查,所以它应该是安全的,但仍然如此。我不确定您在第二条评论中引用的数据来自哪里,但可能生成器决定字节值可以表示为可打印字符并为简洁起见使用它。
【解决方案3】:

您可以使用资源文件 (.rc)。有时它们很糟糕,但对于基于 Windows 的应用程序来说,这是通常的方式。

【讨论】:

    【解决方案4】:

    为什么选择 base64?只需将文件原样存储在一个 char* 中即可。

    【讨论】:

    • 我正在考虑使用 base64,因为我还想优化源代码中使用的空间。
    • @Rookie,三倍的源代码量是如何“优化”它的?
    • 三倍是什么意思?与使用 0xff、0xff、0xff 等方法相比,base64 在源代码中更好地打包数据。见下文: orig: this is a testing text!! base64: dGhpcyBpcyBhIHRlc3RpbmcgdGV4dCEh hexstr: 7468697320697320612074657374696E6720746578742121 decarr: 116,104,105,115,32,105,115,32,97,32,116,101,115,116,105,110,103,32,116,101,120,116,33,33
    • @Rookie,是的,但您不必转义可打印的 ascii 字符。你可以简单地说char *data="this is a testing text!!";
    • 这只是一个例子,说明它会占用多少空间,而原始数据是这里肉眼可见的原始数据长度,我不能在这里粘贴二进制数据……再读一遍标题。
    猜你喜欢
    • 1970-01-01
    • 2021-02-04
    • 1970-01-01
    • 2017-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-24
    相关资源
    最近更新 更多