【问题标题】:Read a file into a string at compile-time [duplicate]在编译时将文件读入字符串[重复]
【发布时间】:2013-11-07 10:44:09
【问题描述】:

我想在一个文件中写一些东西(我们称之为foo.cpp并将它作为一个字符串包含在我的程序中在编译时,类似于方式#include 做到了。

现在我正在使用这个 C 预处理器 #define:

#define toString(src) #src

将一堆代码转换为字符串,如本例所示:

const char* str = toString(
  int x;
  void main(){}
);

如果需要,您可以阅读有关宏字符串化there 的信息。

我想将该代码移动到一个外部文件,该文件将在编译时“链接”。 我不希望文件必须与程序一起分发,如果我要在运行时读取它就会出现这种情况。

我尝试使用如下所示的#include 指令,但编译器拒绝了它:

const char* str = toString(
#include "foo.cpp"
);

g++ 似乎完全糊涂了,但是clang++ 给了我这个错误:

error: embedding a #include directive within macro arguments is not supported

有谁知道是否/如何做到这一点?

注意:我正在使用它来编写我的 GLSL 着色器,尽管我怀疑这些信息是否有用。

PS:在你告诉我这是 this question 的副本之前,将我的代码放在自己文件中的巨大字符串中或使用外部工具(例如 xxd)转储其十六进制表示是对我来说不是“解决方案”,因为它们并不比我目前的方法更好(即更容易/更清洁)。


几年后更新:
我刚刚意识到我从来没有回答过这个问题,因为它被关闭为重复。 当我看到this commit 时,我找到了我正在寻找的答案,它本身基于a comment on this article,并且一直在使用它。

简而言之,一个小的汇编文件包含您想要的文件,并在给定的NAME 下公开它们,其中三个变量NAME_beginNAME_endNAME_len 允许您从 C 访问它们的内容代码。

这样,您就拥有一个只包含您想要的代码的普通文件,并且它会在编译时自动读取,而不必在运行时读取它或跳过xxd 箍。

【问题讨论】:

  • 它是链接问题的副本。您只是不喜欢提供的任何答案。但答案是你不能按照你想要的方式去做,所以你只会得到一堆反映链接问题答案的答案。
  • 你试图为什么平台编译......或者你试图让它跨平台?
  • 我试图理解术语“更好”、“更容易”和“更清洁”如何应用于 this 方法,更不用说其他任何方法了。只是为了理解,您想预处理到源级变量字符串集,然后使用尚未见过的代码将其写入文件,然后从源代码编译所述文件,而您遇到的麻烦是在步骤 1 的“源”中嵌入预处理器语句?
  • @MarkRansom:实际上它是在 C++ 中:raw-string: " d-char-sequenceopt( r-char-sequenceopt) d-char-sequenceopt"(词汇语法要求该序列前面紧跟一个大写的 R。)
  • 我投票重新打开它,因为它有一个 C++ 答案,不适合仅 C 的“重复”。 @rici 为什么不让它成为一个答案,让 OP 决定它是否更好,因为宏 hack 没有做他想做的事?

标签: c++ c include c-preprocessor


【解决方案1】:

您说您不喜欢xxd,因为它使文件无法读取。很公平。编写自己的实用程序以不同格式对数据进行编码会很简单,因为您特别希望字符串作为输入和输出。您可以利用字符串文字连接来使其易于阅读。

const char* str =
#include "foo.h"
    ;

foo.h:

"  int x;" "\n"
"  void main(){}" "\n"

我曾短暂尝试使用 C++11 的 raw string literals,这本来可以在不重新格式化的情况下使用该文件,但它不起作用。 #include 被认为是字符串的一部分,而不是根据需要包含文件。

【讨论】:

    【解决方案2】:

    在这种情况下,最简单的事情就是写一个小 预处理器,它读取你的文件,并输出它的包装 引号中的每一行。我可能会在 Python 中执行此操作,但它是 在 C++ 中也非常简单。假设你已经 得到inputFileoutputFilevariableName来自 某处(可能是argv,但您可能想要导出 后两个来自输入文件名:

    void
    wrapFile( std::istream& inputFile,
              std::ostream& outputFile,
              std::string const& variableName )
    {
        outputFile << "extern char const " << variableName << "[] =\n";
        std::string line;
        while ( std::getline( inputFile, line ) ) {
            outputFile << "    \"" << line << "\\n\"\n";
        }
        std::outputFile << ";" << std::endl;
    }
    

    根据您所包含的文件中的内容,您可能会 必须在输出之前破坏line,以逃避事情 喜欢"\

    如果你想变得花哨,你可以添加一些测试来插入 最后换行上的分号,而不是一行 它自己的,但这并不是必需的。

    这将产生一个'\0' 终止的字符串。鉴于 字符串的可能长度,最好添加 第二个变量的长度:

    std::outputFile << "extern int const "
                    << variableName
                    << "_len = sizeof(" << variableName << ") - 1;\n";
    

    (不要忘记 -1,因为你不想计算 终止'\0' 编译器将添加到您的字符串 文字。)如果您将生成的文件包含在其中 被使用,你不一定需要这个,因为std::beginstd::end 将提供必要的信息(但同样, 不要忘记使用std::end( variableName ) - 1,忽略 '\n')。

    如果您使用的是make,则可以很容易地生成您的 文件取决于被包装的文件,可执行文件 哪个包装(这又取决于来源 上等)。使用 Visual Studios,您需要创建 包装代码的单独项目,如果你用 C++ 编写它 (我为此使用 Python 的原因之一),你可能会 依赖管理有一些问题;视觉工作室 并不是真正为专业工作而设计的(大块 的代码是使用此类技术定期生成的)。

    【讨论】:

    • 使用VS时,只需将文本文件作为资源引入并使用LoadResource函数访问即可;虽然这是特定于 Windows 的。
    • @ZacHowland 是的。我知道 Windows 在这里有几个选项。很遗憾,不是很便携。
    • 很遗憾。我的评论更多的是针对 Visual Studio 并非真正为专业工作而设计的概念。它是......但它专注于特定于 Windows 的专业工作(尽管可能随着他们在开源领域的新发现而改变)。
    • @ZacHowland 这不是您需要机器生成代码的唯一情况。由于各种原因,我从事的每个专业项目都使用了大量机器生成的代码。如果生成代码的程序也是用 C 或 C++ 编写的,Visual Studios 会变得特别困难。
    • 我从来没有遇到过问题(除了人们将生成的代码检查到源代码管理中,但这不是 VS 的问题,也不是特定于它的问题),但话又说回来,我不记得我参与过的任何项目,我们使用 C/C++ 为 C/C++ 编写代码生成。通常,我参与的项目总是使用脚本语言来生成代码。
    【解决方案3】:

    我不太确定您要完成什么,但 Linux 命令行实用程序 xxd 可能是您正在寻找的:

    xxd -i [filename]
    

    将生成一个 C 风格的头文件,其中包含一个数组,其中您的文件内容采用完全二进制编码和一个变量及其长度。

    例子:

    xxd -i /proc/cpuinfo
    

    制作一个文件

    unsigned char _proc_cpuinfo[] = {
      0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x09, 0x3a, 0x20,
      0x30, 0x0a, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x09,
    ...
    };
    unsigned int _proc_cpuinfo_len = 654390;
    

    您可以在代码中包含生成的标头,并通过这些变量访问数组和文件长度。

    【讨论】:

    • 正如我在问题中所说,这个解决方案既不简单也不干净 (这是主观的) 比我目前的方法,但感谢复制/粘贴 :)跨度>
    猜你喜欢
    • 1970-01-01
    • 2012-11-13
    • 1970-01-01
    • 2011-02-24
    • 2014-07-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-20
    • 1970-01-01
    相关资源
    最近更新 更多