用C语言在终端中打印多字节字符

用C语言在终端中打印多字节字符,c,encoding,utf-8,terminal,C,Encoding,Utf 8,Terminal,我一直在试验一个自定义字符串对象(struct),它看起来像这样: typedef struct { int encoding; int length; character * array; } EncodedString; 其思想是,通过指定编码,我可以生成一些使用该编码正确打印字符串的函数,即ASCII或utf-8或utf-16等(请原谅我对字符编码的无知) 现在,我正在尝试打印一个(普通话)汉字:狗 (0x72d7)。我想也许通过逐字打印,它会正常工作,但显然不行

我一直在试验一个自定义字符串对象(struct),它看起来像这样:

typedef struct
{
    int encoding;
    int length;
    character * array;
} EncodedString;
其思想是,通过指定编码,我可以生成一些使用该编码正确打印字符串的函数,即ASCII或utf-8或utf-16等(请原谅我对字符编码的无知)

现在,我正在尝试打印一个(普通话)汉字:狗 (0x72d7)。我想也许通过逐字打印,它会正常工作,但显然不行。它只打印“r?”(分别为0x72和0xd7)。那么,我如何修改这个程序,使其打印字符

#include <stdio.h>

typedef unsigned char character;

typedef struct
{
    int encoding;
    int length;
    character * array;
} EncodedString;

void printString(EncodedString str);

int main(void)
{

    character doginmandarin[] = {0x72U, 0xd7U};
    EncodedString mystring = {0, sizeof doginmandarin, doginmandarin};

    printString(mystring);
    printf("\n");

    return 0;

}

void printString(EncodedString str) // <--- where I try to print the character
{
    int i;
    for(i = 0; i < str.length; i++)
    {
        printf("%c", str.array[i]);
    }
}
#包括
typedef无符号字符;
类型定义结构
{
整数编码;
整数长度;
字符*数组;
}编码字符串;
无效打印字符串(EncodedString str);
内部主(空)
{
字符doginmandarin[]={0x72U,0xd7U};
EncodedString mystring={0,doginmandarin的大小,doginmandarin};
printString(mystring);
printf(“\n”);
返回0;
}

void printString(EncodedString str)//数字
Ox72d7
是要打印的字符的Unicode码点(抽象数字)。当在内存中用两个字节表示为0x72、0xd7时,它将成为该字符的UCS-2代码,而该字符恰好也是其UTF-16编码。但您的终端可能需要UTF-8编码字符。代码点
Ox72d7
的正确UTF-8编码为
0xe7、0x8b、0x97

您可以修改代码以使用UTF-8编码的字符,但是这种编码对于内存表示非常不切实际,因为它为不同的字符生成不同的字节数。这使得获取第n个字符等简单字符串操作变得非常复杂。相反,通常使用固定长度表示法。例如,UCS-2始终为每个字符使用两个字节。然后尽可能晚地完成到外部表示编码的转换,就在打印字符串之前

编辑(来自评论)


UTF-8是一种复杂的编码。从代码点到UTF-8字节的映射并不简单,它涉及到一些按位的混乱。这是一种哈夫曼代码,不同的前缀告诉字符将占用多少字节。此外,以下所有字节均以0b10开头,以检测格式错误的UTF-8。这里描述的是:


为了快速找到我的帖子的三个字节,我在python控制台中键入了以下内容:
u“\u72d7”。encode('UTF-8')
数字
Ox72d7
是要打印字符的Unicode码点(抽象数字)。当在内存中用两个字节表示为0x72、0xd7时,它将成为该字符的UCS-2代码,而该字符恰好也是其UTF-16编码。但您的终端可能需要UTF-8编码字符。代码点
Ox72d7
的正确UTF-8编码为
0xe7、0x8b、0x97

您可以修改代码以使用UTF-8编码的字符,但是这种编码对于内存表示非常不切实际,因为它为不同的字符生成不同的字节数。这使得获取第n个字符等简单字符串操作变得非常复杂。相反,通常使用固定长度表示法。例如,UCS-2始终为每个字符使用两个字节。然后尽可能晚地完成到外部表示编码的转换,就在打印字符串之前

编辑(来自评论)


UTF-8是一种复杂的编码。从代码点到UTF-8字节的映射并不简单,它涉及到一些按位的混乱。这是一种哈夫曼代码,不同的前缀告诉字符将占用多少字节。此外,以下所有字节均以0b10开头,以检测格式错误的UTF-8。这里描述的是:


为了快速找到我的文章中的三个字节,我在python控制台中键入了以下内容:
u“\u72d7”。encode('UTF-8')

您可能应该研究与宽字符(wchar\u t)和多字节字符串相关的c库函数。linux(或据我所知的windows)上的c库实现与unicode兼容。(如果你需要在你的微控制器板上安装这个,你可能会倒霉)。处理utf-8编码和unicode的大多数事情都已经在那里了,所以您不需要自己去做。 下面是一个如何处理一个字符的示例:

#include <stdio.h>
#include <locale.h>
#include <wchar.h>

int main ()
{
  /*
   * use an utf-8 compatible locale.
   */
  setlocale (LC_ALL, "en_US.utf8");
  const wchar_t dog = 0x72d7;

  /*
   * wchar_t strings can contain any character. Create one
   * string containing only the dog.
   */
  wchar_t in[2] = { dog, 0 };
  char out[100];
  /*
   * convert to a multibyte string, returns the number of chars.
   */
  size_t len = wcstombs (out, in, sizeof out);

  printf ("the character '%lc' is %zd bytes (string: '%s')\n", dog, len, out);
}

您可能应该研究与宽字符(wchar\u t)和多字节字符串有关的c库函数。linux(或据我所知的windows)上的c库实现与unicode兼容。(如果你需要在你的微控制器板上安装这个,你可能会倒霉)。处理utf-8编码和unicode的大多数事情都已经在那里了,所以您不需要自己去做。 下面是一个如何处理一个字符的示例:

#include <stdio.h>
#include <locale.h>
#include <wchar.h>

int main ()
{
  /*
   * use an utf-8 compatible locale.
   */
  setlocale (LC_ALL, "en_US.utf8");
  const wchar_t dog = 0x72d7;

  /*
   * wchar_t strings can contain any character. Create one
   * string containing only the dog.
   */
  wchar_t in[2] = { dog, 0 };
  char out[100];
  /*
   * convert to a multibyte string, returns the number of chars.
   */
  size_t len = wcstombs (out, in, sizeof out);

  printf ("the character '%lc' is %zd bytes (string: '%s')\n", dog, len, out);
}

谢谢相反,使用这三个数字起了作用。因此,第一个,
0xe7
告诉处理终端i/o的任何进程,以下两个数字(不确定正确的单词)代表一个代码点?另外,您是如何发现这三个数字的?它们似乎与0x72d7有些不相关。UTF-8是一种复杂的编码。从代码点到UTF-8字节的映射并不简单,它涉及到一些按位的混乱。这是一种哈夫曼代码,不同的前缀告诉字符将占用多少字节。此外,以下所有字节均以0b10开头,以检测格式错误的UTF-8。这里是这样描述的:为了快速找到我文章的三个字节,我在python控制台中键入了:
u“\u72d7”。encode('UTF-8')
谢谢!相反,使用这三个数字起了作用。因此,第一个,
0xe7
告诉处理终端i/o的任何进程,以下两个数字(不确定正确的单词)代表一个单独的cod