在C源代码中、在过程存储器中和/或作为go 往/来自终端的字节流对非ASCII字符进行编码有不同的方法.假设您的系统对所有3个字符都使用UTF-8,这是非常常见的,尤其是在Unix系统(Linux、MacOS)上,字符ğ
被编码为一个2字节的序列C4 9F
,因此字符串"ğğğ"
实际上占用6个字节外加一个空终止符.
要打印单个ğ
,您可以使用write(1, "ğ", 2)
或简单地使用write(1, "ğ", strlen("ğ"))
.
当您对位于str[0]
和str[1]
的各个字节发出两个单独的写入调用时,第一个将输出UTF-8前导字节0xC4,第二个将输出尾部字节0x9F.str[1]
不是字符串中的第二个character,它表示总共具有7个字节的字符数组str
的第二个字节.在一个或两个WRITE调用中写入2个字节的序列在您的终端上产生相同的结果:单个ğ
个字符.
这printf
个调用的行为完全相同:输出2个字节,形成一个字符ğ
(Unicode代码点U-011F,编码为"\xC4\x9F"
).
请注意,'ğ'
是格式错误的字符常量,它不可移植,不应用于表示非ASCII字符.一些C编译器会将其解析为多字节字符常量,如'abc'
,这在历史上是一个令人困惑的奇怪现象,而另一些C编译器,如clang,将生成错误.
以下是一个测试程序:
#include <stdio.h>
#include <string.h>
#include <wchar.h>
int main(void) {
const char *str = "ğ";
const wchar_t *wstr = L"ğ";
printf("str: \"%s\"\n", str);
printf("strlen(\"%s\"): %zu\n", str, strlen(str));
printf("sizeof \"%s\": %zu\n", "ğ", sizeof "ğ");
printf("str[0]: 0x%02hhX, str[1]: 0x%02hhX\n", str[0], str[1]);
//this generates an error:
// character too large for enclosing character literal type
//printf("'%s' = %#x\n", str, 'ğ');
printf("wstr: L\"%s\"\n", str);
printf("wclen(L\"%s\"): %zu\n", str, wcslen(wstr));
printf("sizeof L\"%s\": %zu\n", str, sizeof L"ğ");
printf("wstr[0]: 0x%04X\n", wstr[0]);
printf("sizeof L\'%s\': %zu\n", str, sizeof L'ğ');
printf("L'%s' = 0x%04X\n", str, L'ğ');
return 0;
}
MacOS上的输出:
str: "ğ"
strlen("ğ"): 2
sizeof "ğ": 3
str[0]: 0xC4, str[1]: 0x9F
wstr: L"ğ"
wclen(L"ğ"): 1
sizeof L"ğ": 8
wstr[0]: 0x011F
sizeof L'ğ': 4
L'ğ' = 0x011F