【问题标题】:Return statement being ignored返回语句被忽略
【发布时间】:2017-03-21 12:31:11
【问题描述】:

给未来的读者

编码不要太累。它把你变成了一个小小的丁克。

我的问题是我有两个单独的输出似乎相互冲突。其中一个超出了 return 语句,因此代码正在被执行是令人震惊的。但是,我没有想到使用 Visual Studio 的搜索功能检查所有其他文件,看看是否还有其他原因导致我得到输出。据我当时所知,LoadGLSLFromFile 函数只有一次调用,而实际上有两次调用。

结果让我非常沮丧,因为我肯定没有对该函数的其他调用,并且不知何故必须对我的代码进行优化,这要么弄乱了函数,或者,return 语句没有正常运行(无论出于何种原因)。

如果您要发布问题,我建议您重新评估被视为“相关”的代码。毕竟,您在这里是因为您看不到其他人可以看到的东西。

如果您阅读了本文的内容,您会看到 StoryTeller 试图让我明白我所假设的事情确实不可能发生,并且我的调试方法不正确。讲故事的人,如果您正在阅读本文,我真诚地道歉。

=================================

编辑 2:请注意,我遇到的问题是当我告诉它时该函数没有返回。它在返回之后继续执行,在同一个函数内,直​​到遇到第二个。

所以,我真的不知道为什么会发生这种情况,但这是我的代码。因此,通常我所做的是检查严重故障,如果出现严重问题,我会返回一个已知的“错误”值。但是,返回在多个地方被忽略,并且代码以错误的顺序执行。 (错误顺序见第二张图)

编辑:

我的问题是代码在返回语句之外执行。

#include "Loader.h"
#include <stdio.h>
#include <stdlib.h>
#include <direct.h>
#include <string.h>
#include <GL/glew.h>
#include <GL/GL.h>
#include <GL/GLU.h>
#include <GLFW/glfw3.h>

static const GLchar * VSource[] = {
    "#version 450 core\n"
    "layout (location = 0) in vec4 offset;\n"
    "layout (location = 1) in vec4 color;\n"
    "out VS_OUT {\n"
    "   vec4 color;"
    "} vs_out;\n"
    "void main(void)\n"
    "{\n"
    "   const vec4 vertices[3] = vec4[3](vec4(0.25, -0.25, 0.5, 1.0),\n"
    "                                    vec4(-0.25, -0.25, 0.5, 1.0),\n"
    "                                    vec4(0.25, 0.25, 0.5, 1.0));\n"
    "   gl_Position = vertices[gl_VertexID] + offset;\n"
    "   vs_out.color = color;"
    "}\n"
};

static const GLchar* FSource[] = {
    "#version 450 core\n"
    "in VS_OUT {\n"
    "   vec4 color;\n"
    "} fs_in;\n"
    "out vec4 color;\n"
    "void main(void)\n"
    "{\n"
    "   color = fs_in.color;\n"
    "}\n"
};

static const GLchar* TControlSource[] = {
    "#version 450 core\n"
    "layout (vertices = 3) out;\n"
    "void main(void) {\n"
    "   if(gl_InvocationID == 0) {\n"
    "       gl_TessLevelInner[0] = 5.0;\n"
    "       gl_TessLevelOuter[0] = 5.0;\n"
    "       gl_TessLevelOuter[1] = 5.0;\n"
    "       gl_TessLevelOuter[2] = 5.0;\n"
    "   }\n"
    "   gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
    "}"

};

GLuint LoadAllShaders() {

    LoadGLSLFromFile("glsl", GL_VERTEX_SHADER);


    GLuint VShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(VShader, 1, VSource, NULL);
    glCompileShader(VShader);
    LogCompileStatus(VShader, "VShader");

    GLuint FShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(FShader, 1, FSource, NULL);
    glCompileShader(FShader);
    LogCompileStatus(FShader, "FShader");

    GLuint TShader = glCreateShader(GL_TESS_CONTROL_SHADER);
    glShaderSource(TShader, 1, TControlSource, NULL);
    glCompileShader(TShader);
    LogCompileStatus(TShader, "Tessellation Shader");

    GLuint Program = glCreateProgram();

    glAttachShader(Program, VShader);
    glAttachShader(Program, FShader);
    glAttachShader(Program, TShader);
    glLinkProgram(Program);
    glDeleteShader(VShader);
    glDeleteShader(FShader);
    glDeleteShader(TShader);
    return Program;
}

void LogCompileStatus(GLuint Shader, char* ShaderName) {
    // Checking compile status of VShader
    if (ShaderName == NULL || sizeof(ShaderName) == 0)
        ShaderName = ("Unnamed Shader with ID: %i" + (char)&Shader);
    GLuint ShaderSuccess = GL_FALSE;
    glGetShaderiv(Shader, GL_COMPILE_STATUS, &ShaderSuccess);

    if (ShaderSuccess == GL_TRUE)
        printf("%s successfully compiled\n", ShaderName);
    else {
        GLint LogLength;
        glGetShaderiv(Shader, GL_INFO_LOG_LENGTH, &LogLength);

        char* buffer = (char*)malloc(LogLength);
        glGetShaderInfoLog(Shader, LogLength, NULL, buffer);

        printf("%s failed to compile.\n%s\n", ShaderName, buffer);
        free(buffer);
    }
}


GLuint LoadGLSLFromFile(char* location, GLenum ShaderType) {
    if (sizeof(location) < 6 || strstr(location, ".glsl") == NULL) {
        fprintf(stderr, "Attempted to load invalid file.\n");
        return 0;
    }

    switch (ShaderType) {
    case(GL_COMPUTE_SHADER):
    case(GL_VERTEX_SHADER):
    case(GL_TESS_CONTROL_SHADER):
    case(GL_TESS_EVALUATION_SHADER):
    case(GL_GEOMETRY_SHADER):
    case(GL_FRAGMENT_SHADER):
        break;
    default:
        fprintf(stderr, "Invalid Shadertype\n");
        break;
    }

    FILE* shaderFile = fopen(location, "r");
    if (shaderFile == NULL) {
        fprintf(stderr, "Wurbulgurb\n");
        return 0;
    }
    size_t bufferSize = fseek(shaderFile, 0, SEEK_END);
    printf("File Buffer size: %i\n", (int)bufferSize);


    fclose(shaderFile);
    /*
        glShaderSource(shd, 1, VSource, NULL);
        glCompileShader(shd);
        LogCompileStatus(shd, "VShader");
    */
    

    return 1;
}

主文件:

#include <stdio.h>
#include <stdlib.h>
#include <GL\glew.h>
#include <GL\GL.h>
#include <GL\GLU.h>
#include <GL\wglew.h>
#include <GLFW\glfw3.h>
#include "Loader.h"

#define CL_BUFFER (GLfloat[4]) { 0.3f, 0.3f, 0.3f, 1.0f }

int main(void);
void err(int error, const char * msg);
void keypress(GLFWwindow *window, int key, int scancode, int action, int mods);

static GLfloat attrib[] = { 0.0f, 0.0f, 0.5f, 1.0f };

int main(void) {
    if (!glfwInit())
        return -1;


    GLFWwindow *window = glfwCreateWindow(1024, 768, "Fididdler", NULL, NULL);
    glfwWindowHint(GLFW_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_VERSION_MINOR, 5);
    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
    if (window == NULL)
        return -1;

    LoadGLSLFromFile("./Condoms.glsl", GL_VERTEX_SHADER);

    glfwSetErrorCallback(err);
    glfwSetKeyCallback(window, keypress);

    glfwMakeContextCurrent(window);
    if (glewInit() != GLEW_OK)
        return -1;


    printf("GL Version String: %s \n", glGetString(GL_VERSION));
    GLuint RProg = LoadAllShaders();
    GLuint VAO;
    glCreateVertexArrays(1, &VAO);
    glBindVertexArray(VAO);
    printf("Loading complete");

    


    while (!glfwWindowShouldClose(window)) {
        glClearBufferfv(GL_COLOR, 0, CL_BUFFER);
        glUseProgram(RProg);
        glVertexAttrib4fv(0, attrib);
        glDrawArrays(GL_TRIANGLES, 0, 3);
        
        /* End drawing logic*/

        glfwSwapBuffers(window);
        glfwPollEvents();
    }


    glDeleteVertexArrays(1, &VAO);
    glDeleteProgram(RProg);
    glfwTerminate();
    return 1;
}

void err(int error, const char * msg) {
    printf("Error: %s", msg);
}

void keypress(GLFWwindow *window, int key, int scancode, int action, int mods) {
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, GLFW_TRUE);
    }

    switch (key) {
        case(GLFW_KEY_W): 
            attrib[1] += 0.01f;
            printf("W pressed");
            break;
        case(GLFW_KEY_S):
            attrib[1] -= 0.01f;
            printf("S pressed");
            break;
    }

    switch (key) {
    case(GLFW_KEY_A):
        attrib[0] -= 0.01f;
        printf("A pressed");
        break;
    case(GLFW_KEY_D):
        attrib[0] += 0.01f;
        printf("D pressed");
        break;
    }
}

这是LoadGLSLFromFile("TessControl.glsl", GL_VERTEX_SHADER); 的控制台输出。注意:不应该出现第 3 行,因为在它之前有一个 return 语句。

这是LoadGLSLFromFile("glsl", GL_VERTEX_SHADER); 的控制台输出 注意:不应该出现第 3 行,因为在它之前有一个 return 语句。

有一个 return 语句专门阻止进一步执行,但它仍然执行。我对这种行为感到很困惑,因为据我所知,return 的意思是“立即回到打电话给你的那一行”。

我们将不胜感激。

【问题讨论】:

  • 这个功能没有问题。看到输出包含LoadGLSLFromFile 未打印的行,您在其他地方遇到了问题。
  • ...这是您自己的调用代码,忽略了返回值。我认为很明显,如果您认为这很重要,您需要检查退货状态。
  • 在不相关的注释中,您是否知道sizeof(location) 没有给出location 指向的字符串的长度?试试strlen
  • 你不是在责怪地板吗? “要么是 MSVC,要么是语言,我什么都没做”。打印作为一种调试技术并不可靠!特别是如果您比较保证排序的不同流的打印输出(即stdout和sdterr)。
  • 这里实际上有一个有趣的现象,我想称之为“胆量调试”。当在 SO 上发布类似这样的神秘内容时,您会从经验丰富的程序员那里得到一堆 cmet,他们通常具有这种“胆量调试”能力。也就是说:他们可以根据故障排除经验对实际原因做出看似主观但有资格的猜测。甚至在发布调用方代码之前,您就有了几个这样的合格猜测——结果证明它们是正确的。 “胆量调试”并不总是有效,但它的频率令人惊讶。

标签: c windows


【解决方案1】:

你说返回值被忽略了。这正是您的代码正在做的事情:

GLuint LoadAllShaders() {

    // return value is ignored
    LoadGLSLFromFile("glsl", GL_VERTEX_SHADER);


    GLuint VShader = glCreateShader(GL_VERTEX_SHADER);

因为您不检查返回值,所以没有什么可以阻止您的代码继续运行。

也许您将returnexit() 混淆了。 return 语句从函数返回一个值,以便调用函数可以决定如何继续。 exit 函数导致程序终止,传入的值是程序的返回值。

如果你想退出你的程序,你应该使用exit。如果不是,则需要检查上述代码中的返回值并采取相应措施。

编辑:

这就是MCVE 如此重要的原因。

发布您的主要代码后,问题是您调用了两次LoadGLSLFromFile。您首先直接从main 调用它。然后main 调用LoadAllShaders,后者又调用LoadGLSLFromFile

所以“Wurbulgurb”在第一次调用时打印,而“尝试加载无效文件”或“文件缓冲区大小”在第二次调用时打印。

【讨论】:

  • 问题不在于没有读取返回值。问题在于“return”语句被忽略了,并且在 LoadAllShaders() 函数内部继续执行。
  • @JonathanSchmold return 声明未被忽略。在LoadGLSLFromFile 中打印“尝试加载无效文件”。然后返回 0。此时控制返回到LoadAllShaders,然后运行下面的语句。它一直在执行,因为这正是你告诉它要做的事情。
  • 除了 LoadGLSLFromFile 之外,程序中没有出现“文件缓冲区大小”的点。
  • @JonathanSchmold 是的,但这不是您为错误案例发布的输出的一部分。
  • 是的。它在第一张图片中。
猜你喜欢
  • 2017-09-22
  • 2015-05-15
  • 2021-01-13
  • 2015-08-13
  • 2014-03-04
  • 2016-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多