OpenGL 程序仅在 Visual Studio 2013 的调试模式下工作

OpenGL program works only in Debug mode in Visual Studio 2013

我的小型 OpenGL 应用程序在调试模式下运行良好,但如果我在发布模式下构建它,我经常会遇到此错误:

Shader Creation Error:
- Vertex shader failed to compile with the following errors:
ERROR: 0:22: error(#132) Syntax error: "]" parse error
ERROR: error(#273) 1 compilation errors.  No code generateder code here

奇怪的是,大多数时候都会出现这个错误,但有时程序运行正常。我认为它与文件流有关,但我无法弄清楚它是什么。

这是我代码的对应部分:

    std::ifstream file(fp);
    if(!file) crit_error("Shader Loading", ("file "+fp+" doesn't exist").c_str());

    file.seekg(0, file.end);
    GLint len = GLint(file.tellg());
    file.seekg(0, file.beg);

    GLchar* buf = new GLchar[len];
    file.read(buf, len);
    file.close();

    std::string type = fp.substr(fp.size()-4, 4);
    if(type == ".vsh")
        id = glCreateShader(GL_VERTEX_SHADER);
    else if(type == ".fsh")
        id = glCreateShader(GL_FRAGMENT_SHADER);
    else if(type == ".csh")
        id = glCreateShader(GL_COMPUTE_SHADER);

    glShaderSource(id, 1, (const GLchar**)&buf, &len);
    glCompileShader(id);

    delete[] buf;

好的。我只是尝试了一种不同的阅读方法,它奏效了。

    GLchar* buf = new GLchar[len];

    for(int i = 0; i < len; ++i)
        buf[i] = file.get();    

    file.close();

我认为这是 Visual C++ 编译器的错误。

你的问题出在这里:

file.seekg(0, file.end);
GLint len = GLint(file.tellg());
file.seekg(0, file.beg);

GLchar* buf = new GLchar[len];
file.read(buf, len);
file.close();

此代码读取正好 文件的长度,仅此而已。不幸的是,文件大小实际上并不能告诉您实际需要阅读的内容有多少;如果文件读取退出时间短,它将留在内存 buf 指向的任何垃圾中,然后再分配给您的程序。 这解释了它在调试模式下工作的原因:在调试模式下,缓冲区通常分配得大一点,以允许越界访问检测,并且程序员未初始化的变量和缓冲区被设置为零。虽然对某些调试很有用,但这可能会将常规错误变成 Heisenbugs.

此外,ifstream::read 可能 return 少于请求的字节数,例如,如果您 运行 进入文件结尾的情况,而缓冲区的其余部分保持不变。碰巧 ifstream::get 将 return NUL 如果你到达文件末尾,所以它会用终止 NUL 字节填满你的缓冲区。

读取传递给 C 字符串处理函数的文件的正确方法是:

file.seekg(0, file.end);
GLint len = GLint(file.tellg());
file.seekg(0, file.beg);

GLchar* buf = new GLchar[len + 1];
buf[len] = 0;
file.read(buf, len);
streamsize rb = file.gcount();
if( rb < len ) {
    /* file read short */
    /* either way zero out the remainder of
     * the buffer untouched by the read. */
    memset(buf + rb, 0, len - rb);

    /* should also log some warning message here. */
}
file.close();