Shift-JIS, UTF-8をC言語で扱わないといけなかったけどわからなさ過ぎたので、文字コードとC言語での扱い方について調べたり考えたりした。
嘘は言ってないつもりですが、それでも間違ってたら優しく教えてくださるととても嬉しいです。
特に脚注の疑問が気になっているのでお気軽にぜひ...
文字コード
ASCIIコード
特徴
- 半角英数と制御文字(改行コードとか)だけを表すための文字コード
- 1バイト
- 最上位bitは常に0(上位4bitは7まで)
例):
a → 61
Shift-JIS
特徴
- 日本語を表現するために発明された文字コード
- ASCII文字はそのまま使い、使われていないコード(最上位bitがA以降)に半角カタカナを割り振る → ASCII互換
- 全角文字(平仮名など)の表現のために2バイトのコードを使う → 1~2バイトの可変長
例):
a → 61
ア → B1
あ → 82 A0
1バイト目("あ"の場合は"82")にASCIIで使われていない値が来た場合に2バイト文字と判断し、2バイト目も扱う。
Unicode
特徴
- 全世界の文字を統一的に表現するための文字コード
- 最大21bit
- 複数の符号化方式がある(効率的なデータ保存のため?)
- UTF-8
- UTF-16
- その他割愛
Unicode → UTF-8とか(符号化) → Unicodeのように使う
例):
a → U+0061
あ → U+3042
UTF-8
特徴
- Unicodeの符号化方式
- ASCII文字は1バイト、そのほかは2~4バイトの可変長で表現(日本語は3バイト) → ASCII互換
例):
文字 | Unicode | UTF-8 |
---|---|---|
a | U+0061 | 61 |
あ | U+3042 | E38182 |
文章の先頭につくBOM(Unicodeの符号化方式の判別用のマーク)は3バイトだが、必須でも推奨でもないのでなくてもいい。Excelで開くときにはBOMがないと問題が起こるらしい。
UTF-16
特徴
- Unicodeの符号化方式
- 基本は2バイト固定。2バイト以下で表せないものはサロゲートペアと呼び、2バイト×2の4バイトで表現する(ここは少し自信なし)
- Windows標準で、C#のstringもUTF-16らしい1
例):
文字 | Unicode | UTF-16 |
---|---|---|
a | U+0061 | FF41 |
あ | U+3042 | 3042 |
サロゲートペアについては以下に例がある。 |
Unicode番号が16進数で10000以上の文字を、UTF-8(およびUTF-16)では1 符号単位で表現することができない。
そのため、Unicode番号D800〜DBFFとDC00〜DFFFの組み合わせで表現した仕組み。
https://qiita.com/deco/items/81338e744945f9fef5b2 より
C言語での表現
今までのまとめ。"あ"と"a"の各符号化方式。
文字 | Unicode | UTF-8 | Shift-JIS | UTF-16 |
---|---|---|---|---|
a | U+0061 | 61 | 61 | FF41 |
あ | U+3042 | E38182 | 82A0 | 3042 |
一方、C言語では
-
char
は1バイト。 wchar_t
はsetlocale(LC_ALL, "jpn")
して日本環境にすると2バイト固定。-
wchar_t
は環境によりバイト数が違う。Windowsだと一般に2バイト、Andoroidだと4バイトだったりするよう。
よって"あaあ"という文字列を表現した場合、以下のように認識される。
型 | 符号化方式 | バイト列 |
---|---|---|
char | UTF-8 | E3 81 82 61 E3 81 82 |
char | Shift-JIS | 82 A0 61 82 A0 |
char | UTF-16 | 30 42 FF 41 30 42 |
wchar_t | UTF-8 | E381 8261 E381 82002 |
wchar_t | Shift-JIS | 82A0 6100 82A02 |
wchar_t | UTF-16 | 3042 FF41 3042 |
※脚注がついているものは間違っている可能性大です。教えてください。 |
結論
-
結合するだけとかで、文字数や各文字を識別する必要がないなら
char
だけでいい。 -
文字数を気にしたい場合はShift-JISとUTF-16なら
wchar_t
が完璧。 -
UTF-8で文字数識別が必要とかになったらどうするんだろう。char32_tとか調べきれてない型を使うのだろうか。
-
UTF-8とShift-JISの変換に関して「
MultiByteToWideChar()
でワイド文字(Unicode)に直してからWideCharToMultiByte()
でマルチバイト文字に戻す」ということ文を見た。Windowsのページなので、これはたぶん「char
→ UTF-16(wchar_t
) →char
」という意味の、"Unicode=UTF-16過激派"の表現なんだなと思った。どこかのブログに「microsoftがUnicodeと言ったらUTF-16のことである」って書いてあったし、紛らわしい。