首页 > 解决方案 > 用无用的 printf 调用修复了条件返回值错误

问题描述

我试图为我的简单游戏(学校项目)编写一个简单的碰撞检测函数,直到我添加了一个无意义的printf行(最初它是为了帮助调试)才得到正确的返回值。以某种方式工作。我想知道那个错误可能是什么?以及如何用更“正确”的方式修复它。谢谢。

这是我的函数(变量“rect”(矩形)是一个标准的 SDL 结构,它有 4 个整数成员代表它的高度、宽度和角的 x 和 y):

bool collision(SDL_Rect *rect1, SDL_Rect *rect2) {
    //chekcs to see if rect2 is totally outside of boundaries of rect1
    static bool collided;
    if (rect1->y > rect2->y + rect2->h) {
        printf("");
        collided = false;
        return collided;
    }
    if (rect1->y + rect1->h < rect2->y) {
        printf("");
        collided = false;
        return collided;
    }
    if (rect1->x > rect2->x + rect2->w) {
        printf("");
        collided = false;
        return collided;
    }   
    if (rect1->x + rect1->w < rect2->x) {
        printf("");
        collided = false;
        return collided;
    }
    //returns 1 if none of above is true

    collided = 1;
    return collided;
}

编辑:我使用了静态布尔,因为我试图让 Visual Studio 在监视窗口中显示布尔变量的值,即使它(变量)超出范围,它也不起作用,我忘了删除静态。但是,无论我是否使用静态,问题都存在。

编辑 2:这是调用上述函数的函数(我知道 digonalMovement 需要一个小修复,以使对角线移动时两个方向的速度变慢(目前只有其中一个变慢),但这不应该有什么解决手头的问题):

void player_movement_calc(int player_nr, SDL_Rect char_rects[], Char character[]) {
    // determine velocity
    character[player_nr].x_vel = character[player_nr].y_vel = 0;
    bool collided = collision(&char_rects[0], &char_rects[2]);

    bool digonalMovement = 0;
    if (character[player_nr].up && !character[player_nr].down) {    
        if (digonalMovement)
            character[player_nr].y_vel = -SPEED * 0.86; //multiplying by sin(45)
        else {
            character[player_nr].y_vel = -SPEED;
        }
        digonalMovement = 1;
        if (collided)
            character[player_nr].y_vel -= 2 * character[player_nr].y_vel;
    }
    if (character[player_nr].down && !character[player_nr].up) {
        if (digonalMovement)
            character[player_nr].y_vel = SPEED * 0.86;
        else {
            character[player_nr].y_vel = SPEED;
        }
        digonalMovement = 1;
        if (collided)
            character[player_nr].y_vel -= 2 * character[player_nr].y_vel;
    }
    if (character[player_nr].left && !character[player_nr].right) {
        if (digonalMovement)
            character[player_nr].x_vel = -SPEED * 0.86;
        else {
            character[player_nr].x_vel = -SPEED;
        }
        digonalMovement = 1;
        if (collided)
            character[player_nr].y_vel -= 2 * character[player_nr].y_vel;
    }
    if (character[player_nr].right && !character[player_nr].left) {
        if (digonalMovement)
            character[player_nr].x_vel = SPEED * 0.86;
        else {
            character[player_nr].x_vel = SPEED;
        }
        digonalMovement = 1;
        if (collided)
            character[player_nr].y_vel -= 2 * character[player_nr].y_vel;
    }
    //clears diagonalMovement to make it false for next fram
    digonalMovement = 0;

    // update positions
    character[player_nr].x_pos += character[player_nr].x_vel / 60;
    character[player_nr].y_pos += character[player_nr].y_vel / 60;

    // collision detection with bounds
    if (character[player_nr].x_pos <= 0)
        character[player_nr].x_pos = 0;
    if (character[player_nr].y_pos <= 0)
        character[player_nr].y_pos = 0;
    if (character[player_nr].x_pos >= WINDOW_WIDTH - char_rects[player_nr].w)
        character[player_nr].x_pos = WINDOW_WIDTH - char_rects[player_nr].w;
    if (character[player_nr].y_pos >= WINDOW_HEIGHT - char_rects[player_nr].h)
        character[player_nr].y_pos = WINDOW_HEIGHT - char_rects[player_nr].h;

    // set the positions in the struct 
    char_rects[player_nr].y = (int)character[player_nr].y_pos;
    char_rects[player_nr].x = (int)character[player_nr].x_pos;
}

标签: cdebugging

解决方案


player_movement_calc()函数中,您有collision(&char_rects[0], &char_rects[2]). 看来您应该将玩家的矩形与

    bool collided = collision(&char_rects[0], &char_rects[1]);

您可能正在读取超出char_rects数组末尾的内容,从而导致未定义的行为。由 引起的任何副作用printf,例如为自己的目的分配内存或stdout缓冲区可能会改变程序的行为,例如通过使超出数组末尾访问的内存可读,从而消除崩溃并隐藏错误。

另一个可能的解释是,如果调用collision的结果未被使用并且函数collision没有副作用,编译器可能会省略调用。没有staticprintf,该函数没有副作用(除了由于读取超出数组末尾而导致的崩溃,这无论如何都是未定义的行为)。编译器可能会认为更改该static值是无用的,因为该变量未在任何地方使用且未定义volatileprintf有副作用,所以调用它会变得collision不纯,因此不能省略调用。

尝试理解未定义的行为总是很困难的。调试时,应首先禁用所有优化。如果没有禁用优化,该错误可能是可见的printf,并且使用未优化的代码跟踪代码和观察局部变量应该更容易。

一旦在调试版本中出现可重现的崩溃错误,只需使用调试器向您展示它发生的位置。崩溃错误应该很容易调查。


推荐阅读