桜、抹茶、白、日記

名古屋市在住のC++使いのcoderの日記だったもの。

マルチバイト文字列

Windowsでの開発にどっぷり漬かり過ぎていたのか、全角文字は必ず2バイトだと思い込んでいた。
全角文字を入れると文字が切れるという不具合が挙がってきたので、調査した所自分の無知に気が付く。

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

int main( int nArgC, char** ppArgV )
{
    (void)setlocale( LC_ALL, "" );

    const char szText[] = "あいうえお";
    const size_t nSize = strlen( szText );
    fprintf( stdout, "%s のサイズは %u\n", szText, nSize );

    for ( size_t i = 0; i < nSize; ++i )
    {
        fprintf( stdout, "[%x] %x\n", i, (unsigned char)szText[ i ] );
    }

    (void)fgetc( stdin );
    return 0;
}

Windows上で上記プログラムを実行した場合は・・・

あいうえお のサイズは 10
[0] 82
[1] a0
[2] 82
[3] a2
[4] 82
[5] a4
[6] 82
[7] a6
[8] 82
[9] a8

UTF-8ロケールLinux上で上記プログラムを実行した場合は・・・
※ソースファイルのエンコーディングに注意。ShiftJISのままLinuxコンパイルするとShiftJISロケールになる。

あいうえお のサイズは 15
[ 0] e3
[ 1] 81
[ 2] 82
[ 3] e3
[ 4] 81
[ 5] 84
[ 6] e3
[ 7] 81
[ 8] 86
[ 9] e3
[10] 81
[11] 88
[12] e3
[13] 81
[14] 8a

全角・半角両方の入力を受け付ける場合、ロケールによって格納出来る全角文字列数が変わってしまうな。
因みにワイド文字列ならばロケールに影響されない。

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

int main( int nArgC, char** ppArgV )
{
    (void)setlocale( LC_ALL, "" );

    const wchar_t szText[] = L"あいうえお";
    const size_t nSize = wcslen( szText );
    fwprintf( stdout, L"%ls のサイズは %d\n", szText, nSize  );

    for ( size_t i = 0; i < nSize; ++i )
    {
        fwprintf( stdout, L"[%x] %x\n", i, szText[ i ] );
    }

    (void)fgetwc( stdin );
    return 0;
}

結果

あいうえお のサイズは 5
[0] 3042
[1] 3044
[2] 3046
[3] 3048
[4] 304a

unicode.org > unihan database
http://www.unicode.org/cgi-bin/UnihanGrid.pl?codepoint=U+3042
http://www.unicode.org/cgi-bin/GetUnihanData.pl?codepoint=3042
http://www.unicode.org/cgi-bin/GetUnihanData.pl?codepoint=3044
http://www.unicode.org/cgi-bin/GetUnihanData.pl?codepoint=3046
http://www.unicode.org/cgi-bin/GetUnihanData.pl?codepoint=3048
http://www.unicode.org/cgi-bin/GetUnihanData.pl?codepoint=304a