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

Posted

技术标签:

【中文标题】OpenGL 程序仅在 Visual Studio 2013 中的调试模式下工作【英文标题】:OpenGL program works only in Debug mode in Visual Studio 2013 【发布时间】:2015-06-12 21:24:52 【问题描述】:

我的小型 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;

【问题讨论】:

尝试将buf 写入文件并查看它。也许你被一个或类似的东西关闭了。此处显示的代码还不足以知道这一点。这将有助于您的问题显示您如何找到len,以及fp 是什么。 是的,对不起,我忘了那部分 有人能告诉我为什么我的问题是-1吗?我做错了什么? 您可以考虑阅读How to create a Minimal, Complete, and Verifiable example 来帮助您提出更好的问题。不包括一个好的例子是投票失败的一个常见原因,也是一个要避免的简单原因。很多时候,只需将代码提炼成一个简单的示例就可以帮助您在需要帮助之前解决问题。 【参考方案1】:

你的问题在这里:

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 可能返回的字节数少于请求的字节数,例如,如果您遇到文件末尾的情况,而缓冲区的其余部分保持不变。碰巧ifstream::get 将在您到达文件末尾时返回 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();

【讨论】:

这里也一样。非常感谢。你怎么知道这一切?这在我遇到的任何文章中都没有教过。 @Ankitsinghkushwah:主要是经验。并且阅读大量代码,更重要的是规范!归根结底,为了简洁,教程总是会省略信息。【参考方案2】:

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

    GLchar* buf = new GLchar[len];

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

    file.close();

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

【讨论】:

这不太可能。代码中可能仍然存在问题,并且您暂时设法不小心掩盖了它。您可能会考虑实际检查可能失败的函数的错误代码,例如read 它可能不太可能,但不是很奇怪,它有时在调试模式和发布模式下都能完美运行吗?我刚刚将 file.read() 更改为 file.get() 突然它也可以在发布模式下工作了。 每天有成千上万个程序使用 Visual Studio 开发读取 TB 级文件。这不是编译器错误,而是您的程序中没有共享的东西。 你当然是对的。即便如此,我向您保证,我没有更改任何其他代码,并且这部分是唯一相关的。为什么你认为这是不可能的。想想我的硬件上的应用程序和操作系统之间的所有复杂交互。这可能是一个仅影响我的计算机的问题,仅在使用读取数据进行 OpenGL 着色器加载的情况下。这不太可能但有可能,还是我错了? 我相信一定是这样。希望您不会发现任何其他编译器错误。

以上是关于OpenGL 程序仅在 Visual Studio 2013 中的调试模式下工作的主要内容,如果未能解决你的问题,请参考以下文章

visual studio 2005 opengl 无法解析的外部符号

无法在 Visual Studio 2012 中的 opengl 中绘图

为啥我的 .Net/WinForms 应用程序仅在 Visual Studio 中获得跨线程异常? [复制]

在 Visual Studio 2013 Express 中使用 OpenGL

应用程序仅在安装了 Visual Studio 的 PC 上启动。这种行为的原因可能是啥?

如何在 Visual Studio / OpenGL 中设置 GPU [重复]