繁体   English   中英

如何将文件同时包含在cpp中作为字符串和代码?

[英]How to include a file in cpp as both a string and code?

因此,我希望有一个文件,可以有条件地将其包含为代码或字符串。 像这样:

#define something
#include "myfile.inc" 

#undef something
const char myfileasastring = 
#include "myfile.inc" 

myfile.inc将是这样的简单代码:

something // anything extra here is fine as long as it goes away in the code include case
int myfunc() { return 23; } 

这可能吗? 我试着让#define一些R(“ mystring并用它启动myfile,但这似乎不起作用。

我对此的特定用例是GLSL着色器,当在GL下运行时,我需要将其作为字符串传递给GL驱动程序,但是在软件仿真中运行时,我希望将其编译为CPP代码。

对于这两种情况,我都希望使用相同的文件。 我知道在项目/制造/构建级别上有许多变通办法,甚至只是剪切和粘贴都不是很糟糕,但是拥有一种可移植的编译器级别的方法来完成它会很干净。

未检测到欺骗。 我知道如何将一个或多个文件作为一个或另一个文件包含,但不作为一个文件或与同一文件包含在内。 我也知道如何使用外部工具来做到这一点,我真的只是想知道是否只是想在普通的可移植c ++ 11中使用。 可能不可能。 (尝试再次删除重复标签。如果您仍然认为它是重复对象,请发表评论)

制作一个名为include.cpp的文件,其中包含以下内容:

int f()
{
  return 42;
}

然后, main.cpp (从https://stackoverflow.com/a/25021520/4323获得灵感):

#include <iostream>
#include "include.cpp"

int main()
{
  const char* const str =
    R"(include(include.cpp))"
  ;
  std::cout << str << '\n';
  return f();
}

include()语法是什么? 就是m4! 所以你这样编译:

m4 main.cpp | g++ -x c++ -std=c++11 -

或者,如果您不能在编译命令中使用管道:

g++ -x c++ -std=c++11 <(m4 main.cpp)

如果使用第二个选项,则需要-I规则来告诉编译器在#include "include.cpp"因为源文件“存在”于/dev (这是一种Bash主义)。 您可以改为说include(include.cpp)而不是在顶部使用#include ,无论哪种方法都可以。

该程序从include.cpp打印代码,然后在其中调用函数。

我为使用m4表示歉意,但是它在许多系统上都可用(并且您可以为其他人编写自己的琐碎实现)。

我参与了一个项目,我们做了这样的事情。 我们编写了一个脚本,将代码编译为C ++,然后将主要目标(我们的应用程序)与结果链接起来。 然后,我们还将代码作为资源包含在我们正在构建的应用程序或库中,并在我们希望将其作为glsl传递给OpenGL时从磁盘读取。 我们在Xcode中做到了这一点,它有一个目标,该目标首先将代码作为C ++编译到共享库中,然后将应用程序的第二个目标与生成的共享库链接起来,并将该代码作为文本文件复制到我们的应用程序包中。 您可能可以对make文件或Visual Studio或所使用的任何工具执行相同的操作。

正如评论和解释( John Zwinckuser1118321的其他两个答案) 所言 ,没有外部工具是不可能的。 您似乎在梦见某些(尚不存在)预处理程序指令#include_verbatim ,以使#include_verbatim "myfile.inc"扩展为包含myfile.inc内容的长文字常量。

这还不存在。 你也许对这定制编译器(例如,使用MELT如果与最近编译GCC ...),其中例如将处理#pragma MAKE_VERBATIM_LITERAL_FROM_FILE_CONTENT(MYCONTENT,myfile.inc)来定义预处理符号MYCONTENT是字面内容myfile.inc ; 但这需要付出很大的努力,并且会因编译器而异。

最实用的解决方案是接受使用某些外部工具(例如,简单的make规则即可将myfile.inc转换为myfile.inc.data ,以便可以适当地#include "myfile.inc.data" )。 这将花费您几分钟的开发时间(例如,使用m4awkhexdump ,从FOX工具包 reswrap ...)

如果您不希望依赖某些外部工具,则可以通过在项目内部对编译为transform_to_hex_string.bin的自主transform_to_hex_string.cpp程序进行编码,并添加处理它的make规则(即从transform_to_hex_string.cpp构建transform_to_hex_string.bin ,使其成为项目内部的工具transform_to_hex_string.cpp一侧,并在另一条make规则中运行transform_to_hex_string.bin < myfile.inc > myfile.inc.data 但是它仍然在编译器外部!

自定义编译器(无论是GCC还是LLVM)是特定于编译器的(并且可能是特定于版本的),并且将花费更多的精力(也许一周)。

您可以尝试游说一些C ++标准化委员会成员,使其具有某种语言功能(将来的C ++ 17之后的标准)。

但是请记住,即使在甚至没有文件或目录的假设实现下,也可以阅读C ++标准(在标准意义上, C ++ 11编译器需要处理“ 翻译单元 ”,而不是操作系统意义上的“源文件”) ;从某个IDE填充的某个数据库中处理源代码的编译器将符合标准-并且在上个世纪已经存在此类编译器,也许是IBM的VisualAge

来自最新的C ++ 11规范草案( n3337§2.1 单独翻译

程序的文本保留在此国际标准中称为源文件的单元中。 通过预处理指令#include将源文件连同所有标头(17.6.1.2)和包含的源文件(16.2)一起,减去通过任何条件包含(16.1)预处理指令跳过的任何源行,称为转换单元。 [注意:AC ++程序不需要全部同时翻译。 —尾注] [注:先前翻译的翻译单元和实例化单元可以单独保存或保存在库中。 程序的各个转换单元通过(例如)调用其标识符具有外部链接的功能,操纵其标识符具有外部链接的对象或数据文件的功能来通信(3.5)。 可以分别翻译翻译单元,然后将其链接以生成可执行程序(3.5)。 —尾注]

另请阅读C ++ 11标准的§2.2转换阶段 ,尤其是:

翻译的语法规则中的优先级由以下阶段指定。

  1. 物理源文件字符以实现定义的方式映射到基本源字符集[....]

  2. 紧接换行符的反斜杠字符()的每个实例都将被删除,从而将物理源代码行拼接成逻辑源代码行。 [....]

  3. 源文件被分解为预处理令牌(2.5)和空白字符序列(包括注释)。 源文件不得以部分预处理令牌或部分注释结尾。 12每个注释都用一个空格字符代替。 换行符被保留。 未指定是否保留除换行符以外的每个非空序列的空白字符,还是用一个空格字符替换。 将源文件的字符分为预处理令牌的过程取决于上下文。 [示例:请参见#include预处理指令中的<处理。 —结束示例]

  4. 执行预处理指令,扩展宏调用,并执行_Pragma一元运算符表达式。 如果通过标记串联(16.3.3)产生了与通用字符名称的语法匹配的字符序列,则该行为未定义。 #include预处理指令使命名的标头或源文件从阶段1到阶段4进行递归处理。 然后删除所有预处理指令。

另请参阅有关Quine的Wikipage(计算)

顺便说一句,使用外部工具从外部源生成C ++代码是非常常见的做法: Qt的 Yacc (或GNU bison )和Lex (或Flex )以及ANTLRMOC是众所周知的示例(并将MELT转换为C ++)。

抱歉浪费大家的时间。 我想通了,这很容易:

test.inc:

#ifdef ASSTRING
R"foo(
#else
int do () { return 23; }
// )foo";
#endif

main.cpp

#define ASSTRING
const char s[] =
#include "test.inc";

#undef ASSTRING
#include "test.inc"

printf ( "hello\n%s\n%i\n", s+6, me() );

都将打印代码并运行它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM