LoginSignup
6
1

More than 5 years have passed since last update.

文字列はファイル依存?コンパイラ依存?

Last updated at Posted at 2018-08-23

image001.png

error
warning C4819: ファイルは、現在のコード ページ (932) で表示できない文字を含んでいます。データの損失を防ぐために、ファイルを Unicode 形式で保存してください。
error C2001: 定数が 2 行目に続いています。
error C2143: 構文エラー : ';''for' の前にありません。
warning C4018: '<' : signed と unsigned の数値を比較しようとしました。

Visual C++を使っていてこんなエラーを見たことがあるだろう。

でもこのエラー、文字コードに起因することが原因というのはわかるのだが、ファイルが原因なのか、コンパイラが原因なのかがよくわからなかった。

検証

Clang、VCで以下のコードを実行してみた。
shift_jis、UTF-8、UTF-8N(BOM無し)の3種類でそれぞれファイルを保存してコンパイルを実行させている。
実行すると、文字列がコンソールに16進数で表示される。

main.cpp
#include <iostream>
// int _tmain(int argc, _TCHAR* argv[]) // <- Visual Studio
int main() {
    std::string text = "あ";
    for (int i = 0; i < text.length(); i++) {
        std::cout << std::hex << (int) text[i] << std::endl;
    }
  // system("pause"); //<-VisualStudioのみ
    return 0;
}

今回使った環境は下記

OS コンパイラ エディタ
Mac Clang XCode,CLion
Win VisualC++ VisualStudio

結果は下記

コンパイラ ファイルの文字コード 結果表示
Clang(Mac) Shift_jis ffffff82
ffffffa0
Clang(Mac) UTF-8 ffffffe3
ffffff81
ffffff82
Clang(Mac) UTF-8N ffffffe3
ffffff81
ffffff82
VC(Win) Shift_jis ffffff82
ffffffa0
VC(Win) UTF-8 ffffff82
ffffffa0
VC(Win) UTF-8N Error

ということは、Clangは、ファイルのコードをそのまま通して、VisualStudioはBOMがあればUTF-8であると認識してShiftJISに変換したうえでコンパイルしているということになる。

追記:yumetodo様より、「gccとmsvcは文字コードの変換機能がある。」と教えていただきました。

※結果表示の先頭にあるffffffは、charが1バイトに対してintが4バイトであるため。

wchar_t

文字列をwstring(wchar_t)にしてみた。

main.cpp
// 略
std::wstring text = L"あ";
// 略
コンパイラ ファイルの文字コード 結果表示
Clang(Mac) Shift_jis Error
Clang(Mac) UTF-8 3042
Clang(Mac) UTF-8N 3042
VC(Win) Shift_jis 3042
VC(Win) UTF-8 3042
VC(Win) UTF-8N Error

今度はClangの方でエラーが発生した。

CLionコンソール
Scanning dependencies of target test_unit
[ 50%] Building CXX object CMakeFiles/test_unit.dir/main.cpp.o
main.cpp:6:27: error: illegal character encoding in string literal
    std::wstring text = L"<82><A0>";
                          ^~~~~~~~
1 error generated.
make[3]: *** [CMakeFiles/test_unit.dir/main.cpp.o] Error 1
make[2]: *** [CMakeFiles/test_unit.dir/all] Error 2
make[1]: *** [CMakeFiles/test_unit.dir/rule] Error 2
make: *** [test_unit] Error 2

ようは、元の文字列をワイド文字列に変換出来ないということらしい。

エラーが無い場合すべて3042になっているのは、ワイド文字列が「1文字を1つの整数値で扱えるようにすることを目指した」ことに起因する。

ワイド文字 - Wikipedia

ちなみにUnicode対応表を見ると、UTF-16として3042が割り当てられているのがわかる。

Unicode

image002.png

VCのUTF-8ファイル対応

Visual Studio で UTF-8 で C++ を書いたら心が折れそうになった件 - Hikware.Tech

こちらにあるように/source-charset:utf-8とすればutf-8を読み込めるが、なかなか悲しい現実が待ち受けています。

6
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1