【问题标题】:Backspace and multibyte characters using getchar() in C在 C 中使用 getchar() 退格和多字节字符
【发布时间】:2022-07-20 21:37:37
【问题描述】:

我正在阅读 BeeJ 的 C 编程指南并复制了他的 readline() 函数,该函数从标准输入读取一行。由于它的实现方式,读取多字节字符没有问题,因为它根据接收到的字节总数重新分配空格,因此,它没有 unicode 输入问题。这是一个包含该功能的程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define printPrompt printf("db > ")

/* The readLine function, allocates memory for a short string and
** reads characters into it. When the string's size limit is met,
** the same memory block is reallocated, but twice the size.
** Shamelessly stolen from BeeJ's guide to C programming |=
*/ 

char* read_line(void) {
    int i = 0; /* Position of the current character */
    int linbuf = 4; /* Size of our line in memory, will be
    duplicated once the line length surpasses it */
    char* lin; /* The pointer value to our line */
    int c; /* The value we'll use to accept characters */

    if(  !(lin = malloc( linbuf*sizeof(char)))  )
        return NULL;

    while( c = getchar(), c != '\n' && c != EOF ) {
        /* Check if the amount of bytes accepted has surpassed the
         * amount of memory we've allocated so far */
        if(i == linbuf - 1) {
            /* If it did, reallocate double the space */
            linbuf *= 2;
            char* tmpbuf = realloc(lin, linbuf);
            /* If the space couldn't have been allocated then we'd
             * run out of memory. Delete everything and abort. */
            if(tmpbuf == NULL) {
                free(tmpbuf);
                return NULL;
            }
            /* If we've arrived here that means there were no
             * problems, so we'll assign the newly reallocated
             * memory to "lin" */
            lin = tmpbuf;
        }
        /* Add the new character to our allocated space */
        lin[i++] = c;
    }
    /* If we've received an EOF signal after having read 0
     * characters, we'd like to delete our allocated memory and
     * return a NULL */
    if(c == EOF && i == 0) {
        free(lin);
        return NULL;
    }
    /* Here we'll shrink the allocated memory to perfectly fit our
     * string */
    if(i < linbuf - 1) {
        char* tmpbuf = realloc(lin, i + 1);
        if(tmpbuf != NULL)
            lin = tmpbuf;
    }
    /* Here we'll terminate the string */
    lin[i] = '\0';

    /* Finally, we'll return it */
    return lin;
}

int main(int argc, char* argv[]) {
    char* hey = read_line();
    printf("%s\n", hey);
    return 0;
}

输入
Hello, World! (:
将导致
Hello, World! (:

的输出

多字节字符的输入,例如
שלום, עולם! (:
将导致
שלום, עולם! (:

的正确输出

但是,如果我按退格键,它只会删除一个字节字符,导致输出乱码; (标记为 \b 的退格)的输入:
שיהיה לכם בוקר טוב\b\b\b\b\b\b\b\bערב טוב
最终应该是:
שיהיה לכם ערב טוב
实际上最终是:
�שיהיה לכם בוק�ערב טוב

我的电脑运行 Musl-libc 版本的 Void Linux,我使用 tcc 和 gcc 编译了程序,都产生了相同的结果。

这个问题是否与我的 libc、我的终端(suckless st)、我的内核有关,还是我在代码中缺少的东西?不管是什么情况,我有什么办法可以处理它,最好不使用任何外部库,如 ICU 或你有什么?

【问题讨论】:

    标签: c command-line-interface stdio


    【解决方案1】:

    在规范输入模式下,退格键一次删除一个字节。如果删除的字节数与字符中的字节数不匹配,就会出现问题。当然,对于单字节代码集,字节和字符的大小相同,所以从来没有问题。对于多字节字符,如果字符占用 3 个字节并且您使用了一个退格键,则您的输入已损坏。

    这不是内核或终端驱动程序本身的问题;两者都没有真正意识到多字节字符。所以退格编辑是基于字节的,而不是基于字符的。

    【讨论】:

      猜你喜欢
      • 2017-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多