如何用C预处理器将换行符转为"\n"处理OpenGL着色器代码
OpenGL着色器代码转字符串的预处理器实现方案
很多有OpenGL着色器开发经验的开发者,都希望无需借助额外程序即可将着色器代码转换为带正确换行符的字符串,这样OpenGL编译报错时能直接对应原代码的行号。需求是将代码中的\n或\r\n自动替换为字符串中的"\n",你之前尝试的RAWSTRINGIFY宏无法生效,原因在于R#x写法不符合C/C++语法,且预处理器会将宏参数内的换行符替换为空格,无法保留原代码的换行结构。
以下是几种可行的解决方案:
方案一:C++原始字符串字面量(推荐)
如果使用C++11及以后的标准,直接使用原始字符串字面量即可,无需宏,自动保留换行(无论是\n还是\r\n都会被视为换行符,OpenGL编译时能对应原行号):
const char *sShaderSrc = R"( #version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aNormal; uniform mat4 mModel; uniform mat3 mNormal; uniform mat4 mViewProj; varying vec3 vNormal; void main() { gl_Position = (mViewProj *mModel) * vec4(aPos,1.0) ; vNormal = mNormal*aNormal; } )";
若不想字符串开头多一个空行,可将R"(#version 330 core写在同一行,去掉开头的换行。
方案二:C语言兼容的宏拼接
如果需要兼容无原始字符串支持的C语言,可以用宏简化每行的字符串拼接,自动添加\n:
#define SHADER_LINE(line) #line "\n" const char *sShaderSrc = SHADER_LINE(#version 330 core) SHADER_LINE() SHADER_LINE(layout (location = 0) in vec3 aPos;) SHADER_LINE(layout (location = 1) in vec3 aNormal;) SHADER_LINE() SHADER_LINE(uniform mat4 mModel;) SHADER_LINE(uniform mat3 mNormal;) SHADER_LINE(uniform mat4 mViewProj;) SHADER_LINE() SHADER_LINE(varying vec3 vNormal;) SHADER_LINE() SHADER_LINE(void main()) SHADER_LINE({) SHADER_LINE( gl_Position = (mViewProj *mModel) * vec4(aPos,1.0) ;) SHADER_LINE( vNormal = mNormal*aNormal;) SHADER_LINE(}) ;
编译后会生成带\n的完整字符串,OpenGL报错时的行号与原代码一一对应。
方案三:纯预处理器宏(仅GCC/Clang支持,不推荐)
若坚持要用单宏包裹的方式,可利用GCC/Clang的预处理器扩展,但这种方式会将换行替换为空格,无法保留行号对应关系,不适合用于定位编译错误:
#define STRINGIFY(...) #__VA_ARGS__ #define REPLACE_NEWLINES(text) STRINGIFY(text) #define CONVERT_TEXT_TO_STRING(...) REPLACE_NEWLINES(__VA_ARGS__)
使用示例:
const char *sShaderSrc = CONVERT_TEXT_TO_STRING( #version 330 core layout (location = 0) in vec3 aPos; // ... 其余着色器代码 );
内容的提问来源于stack exchange,提问作者yosmo78
相关产品推荐
相关产品推荐

