【发布时间】:2017-04-17 19:21:11
【问题描述】:
我想创建一个菜单,用户只需按下一个按钮并从屏幕上的选项中进行选择。
我尝试过使用getchar()、fgets(stdin)、gets(),甚至getch()。
我已经转向使用一些内联汇编从标准输入中获取一个字符。 我使用的代码如下:
char io::u_i() {
char a;
__asm__("INT 0x21;" // Interruption vector for input
"MOV %1, %0;" // Move from stdin to a
: "=r" (a) // Output variable
: "r" (stdin) // Input variable
: "%1" // Obfuscated registers
);
return a;
}
如果我对 G++ 如何编译程序集有足够的了解,它应该发送一个中断向量(0x21 是我在网上找到的要求按键的那个),然后将寄存器中的内容移动到 G++ 将接受输入的位置(所以 stdin 在这种情况下)到 G++ 将输出的寄存器。
我之前做过一些常规汇编(AT&T 语法),没有要求用户输入。所以这对我来说是一个新的领域。 G++ 告诉我此时代码中存在错误:
sources/io.cpp:7:11: error: invalid operand for instruction
__asm__("INT 0x21;" // Interruption vector for input
^
<inline asm>:1:6: note: instantiated into assembly here
INT 0x21;MOV %rcx, %r8b;
^~~~~
sources/io.cpp:7:11: error: unknown use of instruction mnemonic without a size suffix
__asm__("INT 0x21;" // Interruption vector for input
^
<inline asm>:1:11: note: instantiated into assembly here
INT 0x21;MOV %rcx, %r8b;
^
但是在我对汇编的介绍中,除了INT 0x21; 之外不需要其他任何东西,所以我看不到 G++ 对我的期望。有 AT&T 语法的内联 ASM 的特定编译器选项吗?
我的代码是否会达到我的预期?
附: : 如果它对你有任何帮助,我正在 macOS Sierra 上编译它,这里是 g++ --version 的输出:
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 8.1.0 (clang-802.0.38)
Target: x86_64-apple-darwin16.5.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
【问题讨论】:
-
在 AT&T 语法中,像 0x21 这样的立即数需要在前面加上
$。Int $0x21。但我更担心的是,这不会作为用户应用程序在 Linux 或 OSX 等操作系统下运行(你似乎在 OSX 上)。int $0x21通常是 DOS 中断。你打算在什么环境下运行这个程序?操作系统开发了吗? -
奇怪,
kbhit()+getch()应该够了 -
其他问题。对于内联扩展 asm,所有寄存器名称都必须有
%%而不仅仅是%。所以%rcx应该是%%rcx等等。您也可以将一个64 位寄存器移动到一个8 位寄存器,您正在尝试使用MOV %rcx, %r8b。 -
您不能在 Mac OS 上使用 MS-DOS API。要消除用户在程序看到用户输入之前按 Enter 键的需要,您需要使用
tcsetattr更改为非规范输入处理。您不需要为此使用程序集。请参阅developer.apple.com/legacy/library/documentation/Darwin/… 或者,您可能希望使用具有更简单接口的 curses 库来处理此类事情。 -
如果您正在寻找 OS/X 和 Linux 解决方案,您可能希望查看这个 SO 答案:stackoverflow.com/a/7469410/3857942。它使用
termios功能修改终端io 设置以创建getch类似功能。
标签: c++ gcc assembly input g++