我正在阅读 BeeJ 的 C 编程指南并复制了他的 readline() 函数,该函数从 stdin 读取一行。由于它的实现方式,它在读取多字节字符时没有问题,因为它根据接收到的字节总数重新分配空间,因此,它在处理 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ערב טוב
这应该最终是:
שיהיה לכם ערב טוב
实际上最终是:
�שיהיה לכם בוק�ערב טוב
我的计算机运行 Void Linux 的 Musl-libc 版本,我使用 tcc 和 gcc 编译该程序,两者都产生相同的结果。
这个问题是否与我的 libc、我的终端(suckless st)、我的内核有关,或者是我在代码中缺少的东西?无论发生什么情况,我有什么办法可以处理它,最好不使用任何外部库,例如 ICU 或你有什么?