C 为什么广角的角色会遭遇不幸?

C 为什么广角的角色会遭遇不幸?,c,ncurses,C,Ncurses,在尝试使用ncurses时,我已经到了需要使用宽字符的地步,用于方框绘制,但也用于其他内容,并且我的情况是每个平铺控件都很有用 但是,在尝试使用以下代码时,我遇到了麻烦: #define _XOPEN_SOURCE_EXTENDED #include <locale.h> #include <curses.h> #include <stdlib.h> #include <time.h> #define ESC 27 int main() {

在尝试使用ncurses时,我已经到了需要使用宽字符的地步,用于方框绘制,但也用于其他内容,并且我的情况是每个平铺控件都很有用

但是,在尝试使用以下代码时,我遇到了麻烦:

#define _XOPEN_SOURCE_EXTENDED

#include <locale.h>
#include <curses.h>
#include <stdlib.h>
#include <time.h>

#define ESC 27

int main() {
  setlocale(LC_CTYPE, "");

  initscr();
  keypad(initscr(),1);
  curs_set(9);
  nonl();

  cchar_t special;
  setcchar(&special, L"æ", 0, COLOR_PAIR(0), NULL);

  cchar_t speshul;
  setcchar(&speshul, L"朝", 0, COLOR_PAIR(0), NULL);

  int c=0;
  do {
    clear();

    mvadd_wch(3,6, &special);
    mvadd_wch(4,6,&speshul);

    refresh();

  } while ((ESC!=(c=getch())));

  endwin();
}
一个单独的问号,其中
特殊
应该是,而
特殊
不应该是

两个角色均未按预期显示

问题在哪里?我如何解决

编辑:回应Petesh的一些额外信息:


预期的结果是打印字符“æ”,并在其下面,朝. 我正在Mac OS X上使用Terminal.app;我正在编译Xcode。

您需要问以下问题:

  • 预期结果是什么(因为它在我的系统上工作)
  • 您使用的终端是什么?即操作系统(windows/etc)、应用程序
  • 是否在编译文件的窗口中编辑该文件
  • 如果您的环境没有正确解释它,并且假设文件处于UTF-8模式,您可能希望在编译行尝试--encoding=UTF-8。如果您使用的是windows,则可以使用UCS-16作为编码

  • 事实证明,魔鬼在于细节

    原来我的问题是对区域设置的调用:

      setlocale(LC_CTYPE, "");
    
    应改为:

      setlocale(LC_ALL, "en_US.UTF-8") // or similar
    
    设置修复了问题,字符现在显示正确。

    代码中还有许多其他“问题”,有些可能与广泛的字符问题有关:


    避免无故调用
    initscr()
    两次。将第一次调用的结果存储在
    窗口
    指针中,或者只需使用内置的
    stdscr
    。另外,对于
    bool
    值,请避免使用数值常量,最好使用命名常量
    TRUE
    FALSE
    。语义是完全不同的

    因此,请使用:

    WINDOW *screen = initscr();
    keypad(screen, TRUE);
    


    9
    不是
    curs\u set()
    的有效参数。手册中:“光标设置例程将光标状态设置为不可见、正常或非常可见,以便可见性分别等于012


    setcchar()
    的第四个参数是
    short color\u pair
    。它需要一个颜色对编号,而不是它的属性掩码(应该应用于
    chtype
    )。我同意,这方面的记录很差。使用
    COLOR\u PAIR()
    仅适用于对0。对于任意对,例如对
    4
    ,请使用:

    setcchar(&special, L"æ", WA_NORMAL, 4, NULL);
    
    也可以使用
    WA_NORMAL
    而不是
    0
    。不要依赖常量值,请使用命名值


    您还应该测试
    错误
    返回。不要假设
    c
    始终包含有效的字符代码:

    while ((c=getch()) != ERR && c != ESC)
    
    此外,如果您确实想使用
    ESC
    作为中断循环的字符,您应该阅读
    ESCDELAY
    。默认情况下,用户按下ESC键和您的程序可用该键之间需要一整秒钟的时间。简单地说,原因是ESC还用于启动转义序列,因此诅咒者必须等待ESC后面是否有其他控制字符,然后才能确定它是一个单独的按键。所以你不能避免延迟,但是你可以把它减少到一个不易察觉的时间,比如说100毫秒。这必须在初始化诅咒之前设置

    在广泛的字符世界中使用
    getch()
    时要小心。对于一个简单的“循环直到ESC”来说,这很好,但是当您想要实际解析用户输入时,用
    get_wch()
    替换它


    最后,您不需要将locale设置为
    “en_US.UTF-8”
    ,因为这将覆盖用户的locale。如果您的终端设置为非
    UTF-8
    的字符编码,或者您的语言不是
    en_US
    ,该怎么办?只需将程序设置为使用用户环境中设置的任何语言环境:


    这与根本不设置区域设置非常不同,因为默认情况下,语言C假定区域设置为
    C
    ,即仅为7位ASCII字符。我相信你应该用函数来创建
    cchar\t
    s(更不用说
    cchar\t
    的实际实现是由实现定义的)。@jwodder:更新代码以使用
    setcchar
    实际上并没有改善事情(这是这个问题的真实答案,特别是关于区域设置问题。
    initscr();
    keypad(stdscr, TRUE);
    
    curs_set(9);
    
    setcchar(&special, L"æ", 0, COLOR_PAIR(0), NULL);
    
    setcchar(&special, L"æ", WA_NORMAL, 4, NULL);
    
    while ((ESC!=(c=getch())))
    
    while ((c=getch()) != ERR && c != ESC)
    
    setenv("ESCDELAY", 100, FALSE);
    
    setlocale(LC_ALL, "");