c++ - 预处理器tomfoolery(字符串化#include)

标签 c++ include opencl c-preprocessor stringification

注意:这个问题与 OpenCL 本身无关...检查最后一段以获得我的问题的简洁陈述。但提供一些背景:

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

我想将 OpenCL 文件作为字符串常量包含在某处,并且最好不使用额外的构建步骤或外部工具(为了跨编译器/跨平台的易用性......即,拒绝 xxd 和类似)。我以为我偶然发现了一种基于 this 线程中第二个答案的技术,如下所示:

#define STRINGIFY(src) #src

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

请注意,如果可能的话,我不希望在我的 OpenCL 代码中嵌入 STRINGIFY 宏(如在上面引用的 SO 问题中所做的那样)。现在,这在 Clang/LLVM 编译器上运行得非常好,但是 GCC 死得很惨(“未终止的参数列表调用宏 STRINGIFY”和与 .cl 文件内容相关的各种语法“错误”出现)。所以,很明显,这种精确的技术不能跨编译器使用(没有尝试过 MSVC,但我希望它也能在那里工作)......我怎样才能最小化地按摩它以便它可以跨编译器工作?

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

编辑:正如 Potatoswatter 指出的那样,上述行为是未定义的,因此不涉及接触要字符串化的文件的真正交叉编译器预处理器技术可能不是t 可能(第一个发现确实对大多数/所有编译器都有效的令人发指的 hack 的人得到了答案)。出于好奇,我最终执行了第二个响应 here 中的建议……也就是说,我将 STRINGIFY 宏直接添加到了我包含的 OpenCL 文件中:

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 文件)。像这样的预处理器方法的一个特点是,由于相邻的字符串被连接起来,你可以写

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

只要 STRINGIFY 宏在两个 .cl 文件中,字符串就会连接起来,让您可以模块化 OpenCL 代码。

最佳答案

标准中最相关的部分是 §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\""

关于c++ - 预处理器tomfoolery(字符串化#include),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6502173/

相关文章:

c - 将 vector 解包为 C 中的变量

c++ - 具有 union 成员的结构是否符合 POD 资格?

c++ - 是否可以将其他文件类型添加到 Visual Studios 清理程序中?

javascript - PHP 'include'函数的现代JS方法

c++ - 为什么 include 指令在头文件之上?

vim - 如何通过 c 文件列出所有包含的头文件(最好在 Vim 中)

c - OpenCL 将 MxN 矩阵转换为方阵

安卓游戏开发。

c++ - 在 wxpython 中打开 Excel

c++ - 'mem_fun' : is not a member of 'std'