0

代码在这里。当我运行我的程序(我将 kbhit 保存为头文件并将其保存在我的程序文件夹中)时,我在使用 kbhit 的第一个实例上获得了未初始化的读取访问权限(我正在使用 DrMemory 进行内存调试)。我包含了 sys/ioctl.h,因为没有它我的程序无法使用 FIONREAD。有问题的是调用 tcsetattr(STDIN, TCSANOW, &term); 我不完全理解这是如何工作的,所以任何帮助将不胜感激。谢谢!

编辑:确切的消息是“UNINITIALIZED READ:读取 12 个字节。系统调用 ioctl.0x5402 参数 #2。” 该行来自 tcsetattr() 调用。此错误是在将 kbhit 保存为 cpp 文件并将其模板化到另一个文件中之后出现的。该程序运行得很好,除了一个错误。

4

1 回答 1

0

这是我修改为实际 C 而不是 C++ 的代码版本,因为它只是出于粗心使用 bool true/false 和 struct 关键字而成为 C++。

哦,是的,不要把它放在头文件中。将它放在一个名为 kbhit.c 的文件中,然后删除或注释掉 test main 函数。在头文件中只写一行:

int _kbhit(void);

或者您可能需要:

extern "C" int _kbhit(void);

这就是您在标题中需要的全部内容。

/**
 Linux (POSIX) implementation of _kbhit().
 Morgan McGuire, morgan@cs.brown.edu
 */
#include <stdbool.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>

int _kbhit(void) {
        static bool initialized = false;

        if (! initialized) {
                // Use termios to turn off line buffering
                struct termios term;
                tcgetattr(STDIN_FILENO, &term);
                term.c_lflag &= ~ICANON;
                tcsetattr(STDIN_FILENO, TCSANOW, &term);
                setbuf(stdin, NULL);
                initialized = true;
        }

        int bytesWaiting;
        ioctl(STDIN_FILENO, FIONREAD, &bytesWaiting);
        return bytesWaiting;
}

//////////////////////////////////////////////
//      Simple demo of _kbhit()

int main() {
        printf("Press any key");
        while (! _kbhit()) {
                printf(".");
                fflush(stdout);
                usleep(1000);
        }
        printf("\nDone.\n");

        return 0;
}

对我来说它看起来是正确的,valgrind 没有抱怨。我没有 Dr. Memory 可以检查。

这段代码的工作原理是它首先用于tcgetattr读取 termios(我认为是终端输入输出设置)结构。然后它通过取消设置 ICANON 位来修改它。佳能是终端的规范设置,包括行缓冲。然后它将新的 termios 值写回终端。与tcsetattr.

ioctl调用获取缓冲区中等待的字节数。如果有字节在等待,那么有人按下了某种键。

于 2019-02-18T06:18:55.383 回答