2012年7月15日日曜日

charのサイズ その2

charのサイズのづつき

charを2バイトにするのは実験。普通なら wchar_tを使うべきでしょう。
早速何が起きているか確認。
$ cat literalTest.c
/* 15.Jul.2012 kei */

#include <stdio.h>
#include <stdlib.h>
#include "redefines.h"

int main() {
 char a = 'あ';
 printf("%x\n", a);
 return EXIT_SUCCESS;
}
$ cc -o literalTest literalTest.c
literalTest.c: In function ‘main’:
literalTest.c:8:11: warning: multi-character character constant [-Wmultichar]
literalTest.c:8:2: warning: large integer implicitly truncated to unsigned type
 [-Woverflow]
$ ./literalTest
8182
$ 

実行はできた。でも
$ echo あ | od -tx1
0000000 e3 81 82 0a
0000004
$ 

だから、e3が掛けているのが判る。
UTF-8は Unicodeの交換用外部フォーマットなので 3バイト。ならば、内部表現の UCS2を使ったらどうか。
$ cc -fexec-charset=ucs2 -o literalTest literalTest.c
literalTest.c: In function ‘main’:
literalTest.c:8:11: warning: multi-character character constant [-Wmultichar]
literalTest.c:8:2: warning: large integer implicitly truncated to unsigned type
 [-Woverflow]
literalTest.c:14:0: internal compiler error: character 0xa is not unibyte in
 execution character set
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://gcc.gnu.org/bugs.html> for instructions.
$ 

おお今度は警告だけでは済まなかった。 gccの組み込み printfがエラーになったのかも。通常のライブラリ関数にしてみる。
$ cc -fno-builtin-printf -fexec-charset=ucs2 -o literalTest literalTest.c
literalTest.c: In function ‘main’:
literalTest.c:8:11: warning: multi-character character constant [-Wmultichar]
literalTest.c:8:2: warning: large integer implicitly truncated to unsigned type
 [-Woverflow]
$ ./literalTest
��$ 

今度は実行までできたが、出力は文字化け。 UTF-8な環境で UCS2を吐き出したのだから当たり前か。
とりあえず確認用に 16進ダンプを書いてみる。
$ cat literalTest.c
/* 15.Jul.2012 kei */

#include <stdio.h>
#include <stdlib.h>
#include "redefines.h"

void lineFeed() {
 byte b = (byte)0xa;
 write(fileno(stdout), &b, 1);
}

void dumpDigit(int d) {
 byte b = (byte)((d < 10) ? (d + 0x30) : (d + 0x61));
 write(fileno(stdout), &b, 1);
}

void dumpByte(int c) {
 int d1 = (c >> 4) & 0xf;
 int d2 = c & 0xf;

 dumpDigit(d1);
 dumpDigit(d2);
}

void dump(char c) {
 int c1 = c >> 8;
 int c2 = c & 0xff;

 dumpByte(c1);
 dumpByte(c2);
 lineFeed();
}

int main() {
 char a = 'あ';

 dump(a);

 return EXIT_SUCCESS;
}
$ cc -fno-builtin-printf -fexec-charset=ucs2 -o literalTest literalTest.c
literalTest.c: In function ‘main’:
literalTest.c:35:11: warning: multi-character character constant [-Wmultichar]
literalTest.c:35:2: warning: large integer implicitly truncated to unsigned type
 [-Woverflow]
$ ./literalTest
4230
$ 

'あ'は UCS2で 0x3042なので、データは大丈夫ようだ。

実例は示さないが、UCS2を使った場合いくつか注意点がある。
ASCIIの範囲でも上位バイトに 0x00が入るため、それなりのprintfでないとすぐに文字列が終端してしまい、なにも表示できない。
wprintfと Lつきのリテラルで英数字を表示することはできるが、漢字などはうまく表示できない。

UCS2な環境にするか、UCS2を扱える printfにするか、printf呼ぶ前に UTF-8に戻す必要があるだろう。

いづれにしても、通常用途ではお勧めできない使い方。

半年で気がついたらぁ

0 件のコメント:

コメントを投稿