東方算程譚

Oriental Code Talk ── επιστημηが与太をこく、弾幕とは無縁のシロモノ。

目次

Blog 利用状況

ニュース

著作とお薦めの品々は

著作とお薦めの品々は
東方熱帯林へ。

あわせて読みたい

わんくま

  1. 東京勉強会#2
    C++/CLI カクテル・レシピ
  2. 東京勉強会#3
    template vs. generics
  3. 大阪勉強会#6
    C++むかしばなし
  4. 東京勉強会#7
    C++むかしばなし
  5. 東京勉強会#8
    STL/CLRによるGeneric Programming
  6. TechEd 2007 @YOKOHAMA
    C++・C++/CLI・C# 適材適所
  7. 東京勉強会#14
    Making of BOF
  8. 東京勉強会#15
    状態遷移
  9. 名古屋勉強会#2
    WinUnit - お気楽お手軽UnitTest

CodeZine

  1. Cで実現する「ぷちオブジェクト指向」
  2. CUnitによるテスト駆動開発
  3. SQLiteで組み込みDB体験(2007年版)
  4. C++/CLIによるCライブラリの.NET化
  5. C# 1.1からC# 3.0まで~言語仕様の進化
  6. BoostでC++0xのライブラリ「TR1」を先取りしよう (1)
  7. BoostでC++0xのライブラリ「TR1」を先取りしよう (2)
  8. BoostでC++0xのライブラリ「TR1」を先取りしよう (3)
  9. BoostでC++0xのライブラリ「TR1」を先取りしよう (4)
  10. BoostでC++0xのライブラリ「TR1」を先取りしよう (5)
  11. C/C++に対応した、もうひとつのUnitTestFramework ─ WinUnit
  12. SQLiteで"おこづかいちょう"
  13. STL/CLRツアーガイド
  14. マージ・ソート : 巨大データのソート法
  15. ヒープソートのアルゴリズム
  16. C++0xの新機能「ラムダ式」を次期Visual Studioでいち早く試す
  17. .NETでマンデルブロ集合を描く
  18. .NETでマンデルブロ集合を描く(後日談)
  19. C++/CLI : とある文字列の相互変換(コンバージョン)
  20. インテルTBBによる選択ソートの高速化
  21. インテルTBB3.0 によるパイプライン処理
  22. Visual C++ 2010に追加されたSTLアルゴリズム
  23. Visual C++ 2010に追加されたSTLコンテナ「forward_list」
  24. shared_ptrによるObserverパターンの実装
  25. .NETでマンデルブロ集合を描く(番外編) ── OpenCLで超並列コンピューティング
  26. StateパターンでCSVを読む
  27. 状態遷移表からStateパターンを自動生成する
  28. 「ソートも、サーチも、あるんだよ」~標準C++ライブラリにみるアルゴリズムの面白さ
  29. インテルTBBの同期メカニズム
  30. なぜsetを使っちゃいけないの?
  31. WPFアプリケーションで腕試し ~C++でもWPFアプリを
  32. C++11 : スレッド・ライブラリひとめぐり
  33. Google製のC++ Unit Test Framework「Google Test」を使ってみる
  34. メールでデータベースを更新するココロミ
  35. Visitorパターンで遊んでみたよ
  36. Collection 2題:「WPFにバインドできる辞書」と「重複を許す検索set」
  37. Visual C++ 2012:stateless-lambdaとSQLiteのぷち拡張
  38. 「Visual C++ Compiler November 2012 CTP」で追加された6つの新機能

@IT

  1. Vista時代のVisual C++の流儀(前編)Vista到来。既存C/C++資産の.NET化を始めよう!
  2. Vista時代のVisual C++の流儀(中編)MFCから.NETへの実践的移行計画
  3. Vista時代のVisual C++の流儀(後編) STL/CLRによるDocument/Viewアーキテクチャ
  4. C++開発者のための単体テスト入門 第1回 C++開発者の皆さん。テスト、ちゃんとしていますか?
  5. C++開発者のための単体テスト入門 第2回 C++アプリケーションの効率的なテスト手法(CppUnit編)
  6. C++開発者のための単体テスト入門 第3回 C++アプリケーションの効率的なテスト手法(NUnit編)

AWARDS


Microsoft MVP
for Visual Developer - Visual C++


Wankuma MVP
for いぢわる C++


Nyantora MVP
for こくまろ中国茶

Xbox

Links

記事カテゴリ

書庫

日記カテゴリ

板挟み

コレ絡み → [C++] UTF-8

ちょいと遅れましたが、先週金曜(12/05)東京タワーの根元にある
機械振興会館で C++ Working Group AdHoc会議 ちゅーのがありました。

いつもの会議は年に数回、C++標準委員会の委員が集まるんですが、
今回のAdHoc会議は一般から有志を募り、来るべきC++0xの仕様に
ついていちゃもんつけよう! って趣旨。 あらかじめ提出されたC++0xの
草案に対するコメントをひとつずつ検討し、上層部に投げるか否かを
決めるっちゅーもんです。

われらわんくま同盟からもなんかそれっぽいヒトが顔出してくれました。
C++標準委員会の名ばかり委員として深く御礼申し上げます。

モメるだろなーと思ってて案の定モメたのが文字コードのおはなし。

たとえば、ですね。
FILE* fp = fopen("日本語.txt","rt");
あるいは
std::ifstream file("日本語.txt");
これ、現在のC/C++では正しく 日本語.txt
オープンできる保証はどこにもないんです。少なくとも言語仕様としては。
コンパイラ/ライブラリ屋さんがちゃんとオープンできるようになんとかしてくれてるだけ。

というのも、文字列(char*,char[],"で囲ったリテラル)は
もともとsingle-byte文字(ASCII)ベースなわけで、
そん中にmulti-byte文字列が格納されたとき、
その文字コードについて言語仕様は一言も言及していません
コード上に書かれた "日本語.txt" がファイル名/パス名として正しく
機能するには、コンパイラが生成する文字列の文字コードと
ファイルシステム(OS-API)が受理するそれとを一致させにゃならん
のですが、言語仕様には触れられていません。

UNICODE(wchar_t)使えばいいわけだけど、そいつのコード上の表現は
L"日本語.txt" みたいにアタマに L が付きます。
なので、ファイル絡みの関数は wchar_t* をパス名として受け付ける版
が必要となります。
ところが、現在の標準ライブラリ仕様には char* 版しか用意されていないんですわ。

もうね、いっそ「コード中に現れるmulti-byte文字列はUTF-8である!」って
言語仕様でゆっちゃえば楽になるわけだけど、そーすっと今まで書かれてきた
あらゆるコードとコンパイラが仕様から外れ、下位互換性が保てなくなる。
いぢりたくてもいぢれないっつーわけ。

投稿日時 : 2008年12月11日 11:19

コメントを追加

# re: 板挟み 2008/12/11 12:00 アキラ

やっぱり標準コンパイルオプションがほしい。
そういうオプションを提供すればcharがUTF-8になってもいいよ、っていうコンパイラ屋さんへの許可でもいいんですが…

# re: 板挟み 2008/12/11 12:03 rigarash

wchar_tがUNICODEとなっている、というのは間違いだと思うのですが。

# re: 板挟み 2008/12/11 12:27 επιστημη

え? そーだっけ。

「UNICODE(内部的にUCS-2かUCS-4かは処理系依存)を
 表現するに十分なハバをもったchar」ってことでダメ?

正しくは?

# re: 板挟み 2008/12/11 13:21 tatar

昔、SunOS(だと思うですが)+X Window Systemをいじっていた時に、wchar_tにeuc-jpが入っていたりした記憶があります。
# locale設定が ja_JP.eucJP だったから、でしょうけれど。

# re: 板挟み 2008/12/11 13:29 aetos

昔、らららさんのトコで epi さんと「wchar_t って Unicode とは限らないよね」って話をした覚えがあるんだけど、ログが見つからない。

# JISC のサイトが重くて規格書が見れないorz

# re: 板挟み 2008/12/11 13:34 επιστημη

あー、ワイド文字とはゆってるけれど、それがUNICODEとはゆってない、てーことか。

L'あ' はワイドな「あ」だけど、UNICODEとは限らない、と。

とはいえこいつがUNICODEじゃなかったためしはないけども ^^;

# re: 板挟み 2008/12/11 13:38 aetos

まぁそんなわけで、規格互換性的には、wchar_t ともまた違う、Unicode であると明記した型が必要になるんじゃあるんめぇか? という気がするんだけれども。
そんなことをすれば混乱は必至だけどね。

# re: 板挟み 2008/12/11 14:10 egtra

> Unicode であると明記した型
それがchar16_t/char32_tですよね、UTF-8ではないですが。
私も参加していましたが、少なくともストリームを開くときのファイル名の引数にwchar_t/char16_t/char32_t文字列を取る多重定義を追加する提案は通ったと記憶しています。

あと、自分もchar8_tが無いのは不思議だと思っています。半分くらいは解決できると思うんですけどね。

# re: 板挟み 2008/12/11 14:15 επιστημη

>> Unicode であると明記した型
> それがchar16_t/char32_tですよね

いまさら言うのもなんだけど、へんなの。
文字幅とencodingとは別物じゃね? て思う。

ucs2char_t, ucs4char_t ならともかくも。

# re: 板挟み 2008/12/11 14:22 aetos

> char16_t/char32_tですよね

そんな型があったのか。

> char8_tが無い

UTF-8 はマルチバイト文字だから、とか?
char16_t、char32_t は(UTF-16のサロゲートを除けば)1文字16bit/32bitで固定だと思うけど、UTF-8は1文字のバイト数が変動するからね。
内部処理はUTF-16/32でやって、I/OのときだけUTF-8に変換するのが楽だから、データ型として提供する必要性は薄いと判断されたのかなー、とか思う。

# re: 板挟み 2008/12/11 14:46 アキラ

u8プレフィックスはありますけど。

# re: 板挟み 2008/12/11 16:11 aetos

あるのか…

# re: 板挟み 2008/12/11 16:14 aetos

Wikipedia
http://ja.wikipedia.org/wiki/C%2B%2B0x#.E6.96.B0.E3.81.9F.E3.81.AA.E6.96.87.E5.AD.97.E5.88.97.E3.83.AA.E3.83.86.E3.83.A9.E3.83.AB

によると(余談だがこのリンクはIE8で機能しない)、

> char型の定義が修正され、少なくともUTF-8の8ビットエンコーディングを格納出来て、コンパイラの基本実行文字セットのあらゆる文字を格納するのに十分な大きさを持つ、とされた。以前は後者だけを満たしていれば良いとされていた。

だそうだ。
つまり、char* を引数に取る関数は、UTF-8 文字列が渡された場合に正しく動作することが保証されるように、ライブラリが見直される、ということになるか。

# re: 板挟み 2008/12/11 17:39 επιστημη

> UTF-8 文字列が渡された場合に正しく動作することが
> 保証されるように、ライブラリが見直される

どぉでしょね。ライブラリいぢられちゃうと以後
fopen("日本語.txt","rt")
は全滅で、ソースコードぜーんぶナメて
fopen(u8"日本語.txt","rt")
に改めよ、ってことになるわけでー

# re: 板挟み 2008/12/12 2:43 aetos

うん? あーそうか。
そうすると、fopen( uchar16/32_t const * ) は新たに追加されるけれど、fopen( char const * ) にマルチバイト文字を渡すのは、u8 であろうがなかろうが、相変わらず動作保証はない、と?

# re: 板挟み 2008/12/12 9:21 rigarash

話題だけ振って、その後発言がなくて申し訳ないです。
僕自身はgcc/glibcな世界しか扱っていないので、問題ないのですが(というかascii以外の文字をプログラミングで使わなくてすむ環境にいる)、
BSDな人のコメントでいえば、

http://www.hi-matic.org/diary/?20081118#18

あたりがまとまっているかと思います。コンパイラとlocaleの関係は悩ましいですね。

# re: 板挟み 2008/12/12 11:14 επιστημη

char8_t かー...
char , unsigned char と区別できる
独立な型: distinguished-type としてですか?

そうなると従来の strほげほげ() 系は型が合わずに全滅すっから
新たに <u8string.h> とか std::u8string とかを導入すっことになるですか?
(UTF8)char8_t* と (UTF16/32)char16_t*/char32_t* の相互変換も必須ですよね。

これはこれで厄介事が増えそうな...

# re: 板挟み 2008/12/12 11:19 もり ひろゆき

んーと、問題になっている点がちょっと不明瞭なんですが・・・。

ちょっと2つ疑問点があります。

1つめは今の議論って要はコードポイントを1文字として認識するにはどうするかってお話なんでしょうか?(^^;

そもそもUnicodeは文字合成の仕組みを持っているのでコードポイント1つでは文字を表現しきれません。

ここでいう文字合成というのはサロゲートペアを除きます。

そのため、Unicodeで1文字を十分に表現できる型となるとUTF-8でなくても1文字単位で可変長となる型が必要になってしまいますね(^^;

Unicodeは結構複雑なので、1文字という単位をどのようにとらえるかによって、単純な固定バイトの型にすることは難しいと思います。

たとえば、サロゲートペアだけでも1文字が4byteになってしまいますし、ディアクリティカルマークなどを利用したものになると4byte6byteとどんどん増えてしまいます。

加えて異体字セレクタなどを利用することになるとさらに・・・という感じで、これがUTF-8で表現することになると1文字10数バイトに及ぶことも近い将来に十分あり得る話だと思いますよ(^^;

2つめはC++が疎いのでよくわからないのですが私が知っていたころのCは型の持つサイズは処理系によって異なっていたのですが、今は規格で決まっているのでしょうか?

なんとなく文脈から見てwchar_tは2byte, uchar16_tも2byte, uchar32_tは4byteのような感じがしていますが認識はあっています?(^^;

その場合、unicodeでUTF-16でも1つのコードポイントは1byteと2byteで表現されるので、コードポイントを表現するだけでも固定幅では厳しいかと思いますが・・・私何か勘違いしています?(^^;

# re: 板挟み 2008/12/12 11:23 もり ひろゆき

あ、間違っていましたね(^^;
UTF-16ではコードポイント1つを表現するには2byteと4byteがあるんでしたね(^^;;;;
失礼しました(^^;;;;

# re: 板挟み 2008/12/12 11:46 επιστημη

もともと「ASCII通れば無問題」がベースになってっとこに
無理くりmulti-byte文字をねぢ込んでるのが諸悪の根源。
そのせいで char だけじゃ足りんくなって wchar_t を導入したがこいつのサイズは処理系の勝手。
それじゃ困るってんで char16_t/char32_t をさらに追加。

結果文字を表現する型が 4通り、std::basic_stringを考えると8通り。
さらに「それらの相互変換とか要るよねー」なんて言い出すと混乱を極めるわけです。

だからいっそencodingを規定して
「文字列はUNICODE、char*での表現形式はUTF8!」
って勅命を発すれば事態は収拾に向かうわけだが、
過去の遺産が邪魔をするわけっす...

# re: 板挟み 2008/12/12 11:47 アキラ

ちなみに、C1xにもchar16_t/char32_t, u/U/u8プレフィックス入りますよ。
http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1333.pdf

標準ライブラリの影響とかは調べてないですけど。

# re: 板挟み 2008/12/12 11:52 soda

二種類の話が混ざってますね。

既にコメントされている通り、wchar_t は UCS-2/4 とは
限りません。UNIX 系だと、wchar_t が UCS-4 固定になっているのは Linux くらいじゃないかな。

もう一つ、ファイルシステム関係のシステムコールに渡すパス名の方も (またファイルシステム上に実際に記録されているパス名も)、UTF-8 であるとは限りません。現行 locale のマルチバイト表現をシステムコールで渡すものが殆んどです。これについては、Linux でも同じです。このため EUC-JP を使ってるシステムは沢山ありますし、ISO-8859-1 を使っているシステムは、本当に山のようにあります。locale 設定ですから、システム管理者によって (場合によっては利用者ごとに) 異なります。

というわけで、Unicode あると決めても何も解決しないでしょうね。むしろ現行システムとの互換性問題が増えるだけじゃないでしょうか。
逆に、特に文字コードを決めなくても、(locale があっている限りは) ちゃんと動くはずです。

# re: 板挟み 2008/12/12 11:59 rigarash

wchar_tの型は処理系依存、c++0xのuchar{16,32}_tは{2,4}byteになっているはずです。

まあ、それだけでなく、コンソールアプリを考えた場合、
1. ソースファイルのエンコーディング
2. ファイルシステム上のファイル名のエンコーディング、
3. ファイルの中身のエンコーディング
4. コンソールの表示のエンコーディング
が全部違うなんてことも普通にありうるので、
ただのバイト列なのか、文字列として変換すべきなのかややこしいですよね。

# re: 板挟み 2008/12/12 12:04 もり ひろゆき

なるほど。

えぴさんの話とsodaさんの話でよく理解できました。

ですが、なんとなくどうにもならない感じもしますねぇ(^^;;;

文字コードの問題は奥深いので(^^;;;;

# re: 板挟み 2008/12/12 13:47 επιστημη

ねぇ (^^;;;

善かれと信じていろいろ突っ込むと余計にひっ掻き回すんちゃうかぁ?
char16_t/char32_tに一抹の不安を覚えるます。

# re: 板挟み 2008/12/12 14:00 もり ひろゆき

んー、そもそもUnicodeのサポートというのも少々疑問が残るところですし・・・。

一口にUnicodeといっても単純に1byte, 2byte, 4byteとかの問題ではないですしねぇ(^^;

文字コードをサポート云々という話を進めると余計にややこしいことになりそうな・・(^^;

データだけを取り扱えば問題が少なそうですが、文字列として取り扱うとなるとやっかいな問題を抱えることになりそうな・・・(^^;;;

やはりC++は難しいですね(^^;;;

てか、今のCももしかして?(^^;;

# re: 板挟み 2008/12/12 14:54 rigarash

処理系依存だとは思うのですが、
CP932なソースファイルに
std::string sample(u8"日本語");
とあったら、sampleはどのようなバイト列になるべきなのでしょうか。
VCだと変換されたものが入ってくれちゃうでしょうけども。

# re: 板挟み 2008/12/12 15:03 επιστημη

んと、ソースがどんなencodingであれ実行時にはUTF8だぞ! てゆーのが u8 のココロやとおもうです。

んだからたとえばバイナリファイル生ストリームに << sample したら
ファイルには UTF8で"日本語"って書いてあるんでないかしら。

# re: 板挟み 2008/12/12 15:25 rigarash

それは、コンパイラがu8"日本語"の文字コードを知っているという前提ですよね。
いろいろなヘッダファイルがあって、それぞれがUTF-8, EUC-JP, ISO-2022-JPで書いてあることも容易に
想像できますが、
それをプリプロセッサにかけて、ひとつの翻訳単位に
したとき、部分部分でu8"日本語"のバイト列は異なるはずですよね?
gccはやばそうだ…

# re: 板挟み 2008/12/12 16:02 επιστημη

ですねー

たとえば encodingの異なる複数のヘッダを
#include したときどう振舞うかは処理系次第でしょうねぇ。

賢いコンパイラなら各ソースのencodingを察して善きにはからうかもしんないし、
特定のencodingだと思い込んで結果バケバケかもしんないし。

# re: 板挟み 2008/12/12 16:06 rigarash

しかも、もしinclude先のヘッダにひきずられることがあれば、
自分のコードをUTF-8にしていても、
u8"日本語"リテラルがバイナリ生ストリームで化けることもありうる、と。

# re: 板挟み 2008/12/12 16:25 επιστημη

んー...あちこちのライブラリを持ち寄ったときに問題を起こしそう。

香ばしい匂いが漂ってます。

# re: 板挟み 2008/12/12 16:41 aetos

#pragma encoding utf8

とか入れるんかなぁ。

# re: 板挟み 2008/12/12 18:58 rigarash

今N2800を読みなおしてました。
2.1.1.1でbasic-source-character以外の文字すべてをuniversal-character-nameとequivalentになるようにしろ、とあるので、
現実的には、phase 1でbasic-source-character以外の文字すべてをISO 10646に変換する、
ということになるのでしょう。

# re: 板挟み 2008/12/12 21:06 通りすがり

ソース中にはASCII以外書かないので、少なくともリテラルの文字コードで困ったことはないなあ。Windowsで日本語が必要ならリソースを使うべきケースがほとんどだし。
パス名の文字コードも、パス名自体に移植性がないので標準規格のレベルで気にしてもしょうがない。

# C++Builder2009????????????String?????????????????????????????????????????? | ???????????????????????? 2010/01/12 13:09 Pingback/TrackBack

C++Builder2009????????????String?????????????????????????????????????????? | ????????????????????????

# ???????????????????????????????????????????????? &raquo; UTF-n???????????????UTF-n???????????? 2011/01/22 0:29 Pingback/TrackBack

???????????????????????????????????????????????? &raquo; UTF-n???????????????UTF-n????????????

タイトル  
名前  
URL
コメント