在编译时将文件读入字符串

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

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

 #define toString(src) #src 

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

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

如果需要,您可以在那里阅读宏字符串化。

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

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

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

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

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

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

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

PS:在你告诉我这是一个重复的问题之前 ,把我的代码放在一个巨大的字符串中,或​​者使用外部工具(例如xxd )来转储它的hex表示对我来说不是“解决方案”,因为它们并不比我现在的方法更好(即更容易/更清洁)。


几年后更新:
我刚刚意识到我从来没有回答这个问题,因为它被重复关闭了。 当我看到这个提交时 ,我找到了我正在寻找的答案,它本身基于对本文的评论 ,并且从那时起一直在使用它。

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

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

我不太确定你要完成什么但是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; 

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

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

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

foo.h中:

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

我简单地尝试使用C ++ 11的原始字符串文字 ,这样可以在不重新格式化的情况下使用该文件,但它不起作用。 #include被认为是字符串的一部分,而不是根据需要包含文件。

在这种情况下最简单的事情是编写一个小的预处理器,它读取你的文件,并输出它用引号括起每一行。 我可能在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的原因之一),你可能会遇到一些依赖关系管理问题; Visual Studios并非真正专为专业工作而设计(使用此类技术定期生成大块代码)。