C++怎么把任意文本文件include成全局字符数组?

inline const char* a_string = R"( #include "a.txt" )";用了raw string, include…
关注者
55
被浏览
47,680

13 个回答

可以用 xxd 、脚本等工具。但是要多一个阶段。

实际上标准委员会的人也为编译时嵌入二进制文件感到困扰。我们知道 C/C++ 预处理器可以包含文件,也可把记号串变成字符串字面量,但这两个功能不能组合到一起。

于是有人提出了编译时嵌入的提案,现在分成两个部分:

  1. P1040R6 “魔法”函数 std::embed ,可以随处选择嵌入一个文件并得到引用嵌入后二进制的 span 。现在的发展方向是引入一个 #depend 预处理指令指定翻译单元可以嵌入的文件。
  2. P1967R2 , N2592 预处理指令 #embed ,功能比较受限而纯粹,即是得到作为嵌入的二进制数据的数组初始化器列表。 #embed 是同时针对 C 和 C++ 提出的。

从作者的测试数据可以看出为编译器增设该功能还是有编译性能优势的。

这个问题我研究过。我的结论是没有完美方法,只有折衷方法,需要稍微修改原始文本。

折衷方法

比如原始 test.glsl 内容为

vec4 mainImage(vec4 fragColor, vec2 fragCoord )
    // Output to screen
    fragColor = vec4(1.0, 0.0, 0.0, 1.0);
    return fragColor;
}

稍微修改,将文本变成 raw string,注意第一行和最后一行

R"(
vec4 mainImage(vec4 fragColor, vec2 fragCoord )
    // Output to screen
    fragColor = vec4(1.0, 0.0, 0.0, 1.0);
    return fragColor;
)"

之后就可以在 C++ 源码中直接 #include

const char *s_shadertoy =
#include "test.glsl"

s_shadertoy 存放的就是原来的文本内容,只是前后各多了一个空行。在实际工程中,需要这样 include 的文本很多都是 json xml OpenGL Shader 等,多了空行没有所谓。

变种

假如不想额外多空行,可以这样写。

// test.glsl
R"(
vec4 mainImage(vec4 fragColor, vec2 fragCoord )
    // Output to screen
    fragColor = vec4(1.0, 0.0, 0.0, 1.0);
    return fragColor;
// main.cpp
const char *s_shadertoy = (char*)
#include "test.glsl"
+ 1;

另外也可以在原始文本中前后添加一点东西,比如可写成

const char *s_shadertoy =
varying vec2        vTexCoord;
uniform vec3        iResolution;    // viewport resolution (in pixels)
uniform float       iTime;          // shader playback time (in seconds)
uniform sampler2D   iChannel0;
uniform sampler2D   iChannel1;
uniform sampler2D   iChannel2;
uniform sampler2D   iChannel3;
#define texture     texture2D
#include "test.glsl"  // 文本插入字符串中间
void main() {
    vec4 fragColor = vec4(0.0, 0.0, 0.0, 1.0);
    vec2 fragCoord = vec2(vTexCoord.x, 1.0 - vTexCoord.y) * iResolution.xy;
    gl_FragColor = mainImage(fragColor, fragCoord);