私のCプログラムを以下に貼り付けます。bash では、プログラム print "char is ", Ω は出力されません。私のロケールはすべて en_US.utf8 です。
#include <stdio.h>
#include <wchar.h>
#include <stdlib.h>
int main() {
int r;
wchar_t myChar1 = L'Ω';
r = wprintf(L"char is %c\n", myChar1);
}
これは非常に興味深いものでした。どうやらコンパイラはオメガをUTF-8からUNICODEに変換しますが、どういうわけかlibcがそれを台無しにします。
まず第一に、%c
-format 指定子はchar
( wprintf -version であっても) を想定しているため、指定する必要があります%lc
(したがって%ls
、文字列の場合)。
次に、ロケールが設定されているようにコードを実行するとC
(環境から自動的に取得されません)。setlocale
環境からロケールを取得するには、空の文字列で呼び出す必要があるため、libc は再び満足しています。
#include <stdio.h>
#include <wchar.h>
#include <stdlib.h>
#include <locale.h>
int main() {
int r;
wchar_t myChar1 = L'Ω';
setlocale(LC_CTYPE, "");
r = wprintf(L"char is %lc (%x)\n", myChar1, myChar1);
}
LIBCの修正を提案する答えの代わりに、これを行うことができます:
#include <stdio.h>
#include <wchar.h>
#include <stdlib.h>
// NOTE: *NOT* thread safe, not re-entrant
const char* unicode_to_utf8(wchar_t c)
{
static unsigned char b_static[5];
unsigned char* b = b_static;
if (c<(1<<7))// 7 bit Unicode encoded as plain ascii
{
*b++ = (unsigned char)(c);
}
else if (c<(1<<11))// 11 bit Unicode encoded in 2 UTF-8 bytes
{
*b++ = (unsigned char)((c>>6)|0xC0);
*b++ = (unsigned char)((c&0x3F)|0x80);
}
else if (c<(1<<16))// 16 bit Unicode encoded in 3 UTF-8 bytes
{
*b++ = (unsigned char)(((c>>12))|0xE0);
*b++ = (unsigned char)(((c>>6)&0x3F)|0x80);
*b++ = (unsigned char)((c&0x3F)|0x80);
}
else if (c<(1<<21))// 21 bit Unicode encoded in 4 UTF-8 bytes
{
*b++ = (unsigned char)(((c>>18))|0xF0);
*b++ = (unsigned char)(((c>>12)&0x3F)|0x80);
*b++ = (unsigned char)(((c>>6)&0x3F)|0x80);
*b++ = (unsigned char)((c&0x3F)|0x80);
}
*b = '\0';
return b_static;
}
int main() {
int r;
wchar_t myChar1 = L'Ω';
r = printf("char is %s\n", unicode_to_utf8(myChar1));
return 0;
}
{glib、libiconv、ICU}を使用して、出力する前にUTF-8に変換します。