【问题标题】:ncurses mvaddch() cursor movement a possible bug?ncurses mvaddch() 光标移动一个可能的错误?
【发布时间】:2015-03-30 09:34:37
【问题描述】:

代码:

#include <ncurses.h>

int main(int argc, char **argv)
{
    initscr();
    noecho();
    cbreak();


    mvprintw(0, 0, curses_version());
    mvprintw(1, 0, "Hello World");
    mvaddch(2, 0, mvinch(1, 4));                 // Why doesn't this work?

    getch();
    endwin();

    return 0;
}

输出:

ncurses 5.9.20130608  
Hello World  

oHello 之后,指针闪烁(等待getch)。

问题:
与在 C 中一样,传递给函数的参数在调用该函数之前首先被评估,mvinch() 将首先被调用,当它返回字符 o 时,将调用mvaddch()
但是为什么字符 o 没有打印在第 2 行(就在 Hello World 下方)?而mvaddch 在当前光标位置打印o(感谢winch 是1,4)。这里mvaddch() 的行为就像addch 一样,不考虑mv 前缀和赋予它的显式移动坐标。为什么?

这可能是 mvaddch() 中的错误还是我遗漏了什么?

编辑:
$ uname -a
Linux Titanic 3.11.0-26-generic #45-Ubuntu SMP Tue Jul 15 04:02:06 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

【问题讨论】:

  • 你在哪个平台上?我在“Hello”中的“H”下方得到了“o”。附带说明一下,使用mvprintw() 打印字符串时要小心。如果字符串恰好包含格式说明符(例如,%s),您就有麻烦了。将mvaddstr() 用于固定字符串会更安全。
  • @Ulfalizer - 因为字符串不是像mvprintw(x, y, str) 中的用户生成的,而是硬编码的,所以我认为这个mvprintw 表单不用担心。至于系统细节,我已经更新了问题。请看一看。
  • 是的,这里不太可能中断。只是值得注意的事情。你用的是什么终端?
  • @Ulfalizer - 当然可以!我正在使用 xterm
  • 顺便说一句,当您不包含标头时它起作用的原因可能是 ncurses 也导出了这些函数的“真实”版本,而是被使用了。

标签: c ncurses cursor-position


【解决方案1】:

问题是mvaddch() 恰好被实现为宏。像这样的电话

mvaddch(2, 0, foo);

扩展为以下内容(删除了一些括号):

wmove(stdscr, 2, 0) == -1 ? -1 : waddch(stdscr, foo);

您可以使用例如gcc -E.

如上所示,foo 将在wmove() 之后计算,这意味着foo 设置的任何光标位置都将优先。

要解决这个问题,您可以将结果从mvinch() 显式保存到chtype 变量中,并在调用mvaddch() 时使用它。

mvinch() 似乎也是一个宏,以wmove()winch() 的形式实现。)

【讨论】:

  • 所以外卖似乎永远不会使用移动函数作为其他移动函数的参数,因为移动函数很可能是作为宏实现的,因此光标移动的顺序可能与预期不同。谢谢!
  • @rootkea:或者更一般地说,当可能涉及宏时要注意意外的评估顺序。另一个常见的与宏相关的问题是参数被评估两次(如在经典 C min/max 宏实现中)。最普遍的建议是保持论点简单且没有副作用。如果您知道有相应的函数,也可以使用括号抑制宏版本。
  • “抑制带括号的宏版本以使用相应的功能”这是一个 ncurses 特定功能,因为它似乎不适用于纯 C 代码?欢迎任何参考链接。
  • @rootkea:它是纯 C 语言。仅当名称后直接有一个左括号时,才会扩展类似函数的宏。 (“直接”在名称和开头括号之间只有空格。)例如,参见gcc.gnu.org/onlinedocs/cpp/Function-like-Macros.html
  • 请注意,如果您抑制宏,则必须调用一个真正的函数:)。标准中的一个非常普遍的要求是,对于许多允许作为宏实现的东西,也必须有一个“真正的”功能。
【解决方案2】:

问题是mvaddchmvinch 都移动了相同的光标位置,而mvinch 是稍后计算的。

结果是“o”被重新添加到读取它的单元格中,并且没有可见的变化。

mvaddchmvinch 通常都是宏。您可以通过#undef'ing 或将宏名称放在括号中来更改此设置,例如,

(mvaddch)(2, 0, (mvinch)(1, 4));

因为move是在函数之外求值的,所以求值的顺序是由宏决定的。

【讨论】:

  • 对不起。我不明白。 mvinch 应该首先评估,因为它是 mvaddch 的参数,对吗?然后当mvaddch 被调用时,我认为mvaddch 操作公共当前光标坐标变量没有问题,而不管其他以前调用的光标位置操作函数做了什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-28
  • 2011-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-10
相关资源
最近更新 更多