【问题标题】:Why does switch always run default? (with break; included)为什么switch总是默认运行? (带休息;包括)
【发布时间】:2014-08-08 02:03:09
【问题描述】:

C++ 新手尝试在二维数组上制作简单的文本游戏。

当我使用switch 语句时,如图所示。不管发生什么,它总是会打印默认值。

从其他线程和论坛中,我发现它可能与 getch() 有关,并且它返回 char 和 \n。

我已经尝试了一个小时,但我无法解决这个问题。我使用getch() 的原因是:C++ change canonical mode in windows(供参考)。

现在是我的部分代码:

//Set up game field
generateField();
setPlayerStart();

//printGameInfo(); TO BE MADE

//Start game while loop
int userInput;

do{
    //system("cls"); DISABLED FOR TESTING PURPOSES
    printField();
    userInput = getch();

    switch(userInput){
        case 72:{ //ARROW UP
            cout << "1What" << endl; //ALSO FOR TESTING PURPOSES
            break;
        }

        case 80:{ //ARROW DOWN
            cout << "2What" << endl;
            break;
        }

        case 75:{ //ARROW LEFT
            cout << "3What" << endl;
            break;
        }

        case 77:{ //ARROW RIGHT
            cout << "4What" << endl;
            break;
        }

        case 113:{ //"q"
            return false; //Quit game
        }

        default:{
            cout << "Default..." << endl;
        }
    }
} while(userInput != 5);

【问题讨论】:

  • 你没有default,是吗?
  • 72 更可能是H。 getch 不读取按键,它读取字符。
  • 哇,我的错。 Ctrl-C Ctrl-V 显然不是那么容易。已编辑
  • 当您遇到不应该经常发生的default 案例并输出某种日志或调试消息时,请首先包含将您带到default 的实际变量。
  • @RetiredNinja:或者,更好的是,识别箭头键发送的序列。忽略任何事情都可能导致问题。

标签: c++ windows switch-statement


【解决方案1】:

嗯,我假设你忘记了如何接收扩展密钥..

扩展键时带有0xe0,功能键(F1-F12)时带有0x00

改变它

userInput = getch();

进入

userInput = getch();
if (userInput == 0xe0) // for extended keys
{
    userInput = getch();
}
else if (userInput == 0x00) // for function keys
{
    userInput = getch();
}

【讨论】:

  • 这个总是忽略第一个键。如果你想识别,比如说,字母或数字怎么办?
  • @KeithThompson 正如我所说-这是接收扩展密钥的方法。如果你想同时接收普通和扩展密钥,你应该userInput = getch(); if (userInput == 0xe0) userInput = getch();
  • 额外的值也可能是0,至少F1-F10是这样。
  • 我是说你应该注意getch()返回的both结果。通过您的方法,悄悄地忽略0xe0,您无法区分向上箭头和H。当且仅当它看到0xe0 后跟'H' 时,代码应该识别一个向上箭头。
  • @ikh 来自documentation 和一个快速测试程序。关于序列的好点,我之前没有考虑过冲突。
【解决方案2】:

由于这是Windows,您可以使用 ReadConsoleInput 来读取关键事件。我已经将这些部分分成了函数,但我真的不认为handleInput 的返回语义有那么好。

#include <iostream>
#include <stdexcept>
#include <windows.h>

HANDLE getStdinHandle() {
    HANDLE hIn;
    if ((hIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
        throw std::runtime_error("Failed to get standard input handle.");
    }

    return hIn;
}

WORD readVkCode(HANDLE hIn) {
    INPUT_RECORD rec;
    DWORD numRead;
    while (ReadConsoleInput(hIn, &rec, 1, &numRead) && numRead == 1) {
        if (rec.EventType == KEY_EVENT && rec.Event.KeyEvent.bKeyDown) {
            return rec.Event.KeyEvent.wVirtualKeyCode;
        }
    }

    throw std::runtime_error("Failed to read input.");
}

bool handleInput(WORD vk) {
    switch (vk) {
        case VK_UP:
            std::cout << "up\n";
            break;

        case VK_DOWN:
            std::cout << "down\n";
            break;

        case VK_LEFT:
            std::cout << "left\n";
            break;

        case VK_RIGHT:
            std::cout << "right\n";
            break;

        case 'Q': //it's Windows; ASCII is safe
            return true;
    }

    return false;
}

int main() {
    try {
        auto hIn = getStdinHandle();

        while (auto vk = readVkCode(hIn)) {
            if (handleInput(vk)) {
                return 0;
            }
        }
    } catch (const std::exception &ex) {
        std::cerr << ex.what();
        return 1;
    }
}

其他有用的链接:

【讨论】:

  • +1 用于基于 api 的解决方案 - getch 看起来很旧,不是吗?
  • @ikh,它来自conio.h,用于 DOS,所以是的。
  • 尤其是getch() - 尽管它被广泛使用o^o
  • 非常感谢您花时间回答这个问题。看起来真的很好,但有点过头了。明天我会再看一遍,因为现在是凌晨 1 点,然后我会浏览文档。再次感谢。
  • @LuukV,当您阅读 Windows API 文档已有几年时间时,这会容易得多,但是是的,它只是遵循文档并检查错误(我认为包含这些会很有用,但我并没有使用std::system_error 或GetLastError)。
猜你喜欢
  • 2019-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多