Исправлена ​​ошибка условного возврата с помощью бесполезного вызова printf - PullRequest
1 голос
/ 10 апреля 2019

Я пытался написать простую функцию для обнаружения столкновений для моей простой игры (школьный проект) и не мог получить из нее правильное возвращаемое значение, пока не добавил бессмысленную строку 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;
}

Редактировать: я использовал static bool, потому что я пытался заставить Visual Studio отображать значение булевой переменной в окне наблюдения, даже когда она (переменная) находилась вне области видимости, она не работала, и я забыл удалить static.Проблема в том, использую ли я статическое или нет.

Редактировать 2: Вот функция, которая вызывает функцию выше (я знаю, что digonalMovement нуждается в небольшом исправлении, чтобы замедлить скорость в обоих направлениях при движении по диагонали(в настоящее время только 1 из них становится медленнее), но это не должно иметь никакого отношения к рассматриваемой проблеме):

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;
}

1 Ответ

1 голос
/ 10 апреля 2019

В функции 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 не имеет побочных эффектов. Без static и printf функция не имеет побочного эффекта (кроме сбоя, вызванного чтением за пределами массива, что в любом случае является неопределенным поведением). Изменение значения static может быть сочтено бесполезным компилятором, так как эта переменная нигде не используется и не определена volatile. printf имеет побочные эффекты, поэтому при его вызове collision не очищается, поэтому вызов не может быть отменен.

Всегда трудно понять смысл неопределенного поведения. При отладке вы должны сначала отключить все оптимизации. Ошибка, вероятно, видна без printf с отключенными оптимизациями, отслеживание кода и отслеживание локальных переменных должно быть намного проще с неоптимизированным кодом.

Если в отладочной сборке есть воспроизводимая ошибка сбоев, просто используйте отладчик, чтобы показать вам, где это происходит. Крушение ошибок должно быть легко расследовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...