GLSL着色器编译失败:自定义文件读取函数引发非法字符问题求助
着色器文件读取函数导致编译错误问题解决
我在跟着C++版的OpenGL教程学习,为了避免把着色器代码硬编码进程序,写了一个从文件读取着色器的函数:
const char* ReadShader(const char* p_ShaderLocation) { std::ifstream ShaderStream; std::stringstream Buffer; ShaderStream.open(p_ShaderLocation); if (!ShaderStream) { std::cout << "File: " << p_ShaderLocation << " can't be opened!" << '\n'; return 0; } if (ShaderStream.is_open()) { Buffer << ShaderStream.rdbuf(); ShaderStream.close(); return Buffer.str().c_str(); } else if (!ShaderStream.is_open()) { std::cout << "File: " << p_ShaderLocation << " can't be read!" << '\n'; return 0; } }
运行后出现编译错误:
ERROR: Vertex Shader Compilaton Failed ERROR: 0:2: 'Ç' : unexpected token ERROR: 0:2: '' : compilation terminated ERROR: 2 compilation errors. No code generated. ERROR: Fragment Shader Compilaton Failed ERROR: 0:2: '' : syntax error, unexpected IDENTIFIER ERROR: 1 compilation errors. No code generated.
问题根源
你的ReadShader函数返回的是临时字符串的野指针。Buffer.str()会创建一个临时的std::string对象,调用c_str()得到的指针仅在这个临时对象存活时有效。函数执行完毕后,临时对象被销毁,指针指向的内存变成无效区域,OpenGL读取时就会拿到乱码或垃圾数据,这就是你看到奇怪字符和编译错误的原因。
修复方案
方案一:返回std::string(推荐,无需手动管理内存)
修改函数返回类型为std::string,使用时再调用c_str()传给OpenGL:
std::string ReadShader(const char* p_ShaderLocation) { std::ifstream ShaderStream; std::stringstream Buffer; ShaderStream.open(p_ShaderLocation); if (!ShaderStream) { std::cout << "File: " << p_ShaderLocation << " can't be opened!" << '\n'; return ""; } Buffer << ShaderStream.rdbuf(); ShaderStream.close(); return Buffer.str(); }
使用示例:
std::string vertexShaderSource = ReadShader("vertex.shader"); const char* vertexShaderCode = vertexShaderSource.c_str(); // 将vertexShaderCode传入OpenGL进行编译
方案二:动态分配内存(需手动释放)
如果一定要返回const char*,可以动态分配内存存储字符串内容,但记得使用完后要手动释放,避免内存泄漏:
const char* ReadShader(const char* p_ShaderLocation) { std::ifstream ShaderStream; std::stringstream Buffer; ShaderStream.open(p_ShaderLocation); if (!ShaderStream) { std::cout << "File: " << p_ShaderLocation << " can't be opened!" << '\n'; return nullptr; } Buffer << ShaderStream.rdbuf(); ShaderStream.close(); std::string shaderStr = Buffer.str(); char* shaderCStr = new char[shaderStr.size() + 1]; std::strcpy(shaderCStr, shaderStr.c_str()); return shaderCStr; }
使用后记得释放内存:
const char* vertexCode = ReadShader("vertex.shader"); // 执行编译操作... delete[] vertexCode; // 释放动态分配的内存
额外优化
原函数中的else if (!ShaderStream.is_open())分支是多余的——前面已经通过!ShaderStream判断了文件打开失败的情况,走到is_open()判断时文件必然是打开状态,所以可以删掉这个分支简化代码。
内容的提问来源于stack exchange,提问作者setorano
相关产品推荐
相关产品推荐

