预处理器tomfoolery(stringifying a #include) [英] Preprocessor tomfoolery (stringifying a #include)

查看:271
本文介绍了预处理器tomfoolery(stringifying a #include)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:这个问题与OpenCL无关...检查最后一段是否对我的问题做了简洁的陈述。但提供一些背景:

Note: This question has nothing to do with OpenCL per se... check the last paragraph for a succinct statement of my question. But to provide some background:

我正在编写一些使用OpenCL的C ++代码。我喜欢将OpenCL内核的源代码保存在自己的文件中,以便于编码和维护(而不是直接将源代码作为字符串常量嵌入到关联的C ++代码中)。这不可避免地导致了一个问题,即当它分配二进制文件时,如何将它们加载到OpenCL运行时---理想情况下,OpenCL源包含在二进制文件中,这样二进制文件不需要在特定的地方在某些目录结构中知道OpenCL源代码在哪里。

I'm writing some C++ code that makes use of OpenCL. I like to keep the source for my OpenCL kernels in their own files, to keep coding and maintenance easy (as opposed to embedding the sources directly as string constants in associated C++ code). This inevitably leads to the question of how to load them into the OpenCL runtime once it comes time to distribute binaries---ideally, the OpenCL source is included in the binary, so that the binary doesn't need to be in a specific place within some directory structure to know where the OpenCL source code is.

我想将OpenCL文件作为字符串常量包括在某处,最好不使用额外的构建步骤或外部工具(用于交叉编译/跨平台易用性,即,no到 xxd 等)。我想我在这个的基础上偶然发现了一个基于第二个答案的技术。线程,像这样:

I'd like to include the OpenCL files as string constants somewhere, and preferably without the use of additional build steps or external tools (for cross-compiler/cross-platform ease of use... i.e., no to xxd and the like). I thought I'd stumbled on a technique based on the second answer in this thread, like so:

#define STRINGIFY(src) #src

inline const char* Kernels() {
  static const char* kernels = STRINGIFY(
    #include "kernels/util.cl"
    #include "kernels/basic.cl"
  );
  return kernels;
}

注意,我不想嵌入 STRINGIFY 宏在我的OpenCL代码,如果可能的话(如在上面引用的SO问题)。现在,这工作奇妙地在Clang / LLVM编译器,但GCC死了一个可怕的死亡(未终止参数列表调用宏STRINGIFY和各种语法错误相关的.cl文件的内容出现)。所以,显然这个确切的技术是不可用的编译器(没有尝试过MSVC,但我想它也在那里工作)...我如何最小地按摩,使其工作在编译器?

Note that I'd prefer not to embed the STRINGIFY macro in my OpenCL code if at all possible (as was done in the above referenced SO question). Now, this works wonderfully on the Clang/LLVM compiler, but GCC dies a horrible death ("Unterminated argument list invoking macro STRINGIFY" and various syntax "errors" related to the contents of the .cl files appear). So, clearly this exact technique isn't usable across compilers (haven't tried MSVC, but I'd like it to work there too)... How could I massage it minimally so that it works across compilers?

总之,我想要一个符合标准的技术,将文件的内容作为C / C ++字符串常量,而不调用外部工具或者使用无关的代码来污染文件。想法?

In summary, I'd like a standards-compliant technique for including the contents of a file as a C/C++ string constant without invoking external tools or polluting the files with extraneous code. Ideas?

EDIT :Potatoswatter指出,上述的行为是未定义的,所以一个真正的交叉编译器预处理器技术, t涉及触摸要被string -ified的文件可能是不可能的(第一个人找出一个令人发指的黑客,工作为大多数/所有编译器获得答案点)。对于好奇的问题,我最后执行了第二个响应中建议的内容此处 ...就是说,我将 STRINGIFY 宏直接添加到我包含的OpenCL文件中:

EDIT: As Potatoswatter pointed out, the behavior of the above is undefined, so a truly cross-compiler preprocessor technique that doesn't involve touching the files-to-be-stringified probably isn't possible (first person to figure out a heinous hack that does work for most/all compilers gets the answer points). For the curious, I ended up doing what was suggested in the second response here... that is, I added the STRINGIFY macro directly to the OpenCL files I was including:

code> somefile.cl :

In somefile.cl:

STRINGIFY(
  ... // Lots of OpenCL code
)

somefile.cpp

#define STRINGIFY(src) #src

inline const char* Kernels() {
  static const char* kernels =
    #include "somefile.cl"
    ;
  return kernels;
}

这在我试过的编译器中有效(Clang和GCC因为它在宏内没有预处理器指令),并且至少在我的上下文中不是太大的负担(即,它不干扰语法高亮/编辑OpenCL文件)。这种预处理器方法的一个特点是,由于相邻的字符串被连接,你可以写

This works in the compilers I've tried it in (Clang and GCC as well, since it doesn't have preprocessor directives inside the macro), and isn't too large a burden at least in my context (i.e., it doesn't interfere with syntax highlighting/editing the OpenCL files). One feature of preprocessor approaches like this one is that, since adjacent strings get concatenated, you can write

inline const char* Kernels() {
  static const char* kernels =
    #include "utility_functions.cl"
    #include "somefile.cl"
    ;
  return kernels;
}

,只要STRINGIFY宏都在

and as long as the STRINGIFY macro is in both .cl files, the strings get concatenated, allowing you to modularize your OpenCL code.

推荐答案

标准的最相关部分是§16.3/ 10:

The most relevant part of the Standard is §16.3/10:


由外部最匹配的括号限定的预处理标记序列形成列表的函数式宏的参数。列表中的单个参数由逗号预处理令牌分隔,但匹配的内部括号之间的逗号预处理令牌不会分隔参数。如果(在参数替换之前)任何参数没有预处理令牌,则行为是未定义的。如果在参数列表中有预处理标记序列,否则这些预处理标记将作为预处理指令,则该行为是未定义的。

The sequence of preprocessing tokens bounded by the outside-most matching parentheses forms the list of arguments for the function-like macro. The individual arguments within the list are separated by comma preprocessing tokens, but comma preprocessing tokens between matching inner parentheses do not separate arguments. If (before argument substitution) any argument consists of no preprocessing tokens, the behavior is undefined. If there are sequences of preprocessing tokens within the list of arguments that would otherwise act as preprocessing directives, the behavior is undefined.

要点:


  • 您需要将头文件包含在一对括号中,以便宏不会认为文件引入另一个参数。

  • 在参数列表中放置 #include 这个括号也会被字符串化,是正式未定义的行为,所以这将是不可移植的。编译器正式不知道你想要的结果字符串是#include \kernels / util.cl\

  • You need to enclose the header files within a pair of parentheses so the macro doesn't think that every comma character in the file introduces another argument. These parentheses will also be stringized, but shouldn't be hard to work around.
  • Putting #include in an argument list at all is officially undefined behavior, so this is going to be unportable. The compiler officially doesn't know whether you want the resulting string to be "#include \"kernels/util.cl\"".

这篇关于预处理器tomfoolery(stringifying a #include)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆