9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

gcc の -finput-charset で UTF-8 以外を指定すると大変な目に合った

Posted at

gcc にはソースファイルの入力文字セットを指定するオプション -finput-charset があります。これは可能な限り使用せずに、ソースファイルの文字セットは UTF-8 にしよう! という話です。

そもそも -finput-charset って何?

ソースファイルの文字セットを指定するためのオプションです。デフォルトは UTF-8 です。

cp932 (Shift-JIS) でソースが書かれていて、このオプションをつけていないとまれに問題を起こします。例えば、以下のコードは -finput-charset なしでは n = 0 を出力します(わざとらしい例ですが)。

#include <iostream>
int main() {
    int n = 0;
    // ここで n に代入する値の意味は、同梱の資料を見てください。
    // see: 〇〇設定表
    n = 42;
    std::cout << "n = " << n << std::endl;
}

昔懐かしい の文字化け問題ですね。cp932 の は 0x95 0x5c というバイト列ですが、0x5c は \ のため、コメント行末尾に \ が来たと解釈されて次の行 n = 42 もコメント扱いされます。

-finput-charset=cp932 をつければ、コンパイラは文字 を 1 文字と正しく解釈するので上のコードはちゃんと n = 42 を出力します。

問題が発生する例

問題はここからです。

試しに -finput-charset=cp932 をつけて、以下の 1 行のコードをコンパイルしてみましょう。

forward_listをincludeするだけのコード
#include <forward_list>

このコードはコンパイルが通りません。gcc 8.2.0, 7.3.0, 5.5.0 で確認しましたが全てエラーになりました。

$ echo '#include <forward_list>' > tmp.cpp
$ g++ -finput-charset=cp932 tmp.cpp
In file included from tmp.cpp:1:0:                                                                                     
/usr/include/c++/7/forward_list:38:31: error: failure to convert cp932 to UTF-8                                        
 #include <bits/forward_list.h>                                                                                        
                               ^
 (...以下略...)

なぜこうなるかというと、gcc の forward_list のヘッダファイル内で UTF-8 文字を使っているためです。

入力文字セットに cp932 を指定したので、gcc は iconv を使ってソースファイルを cp932 から gcc が使用するソース文字セットに変換してコンパイルします。そこで #include <forward_list> から読み込むヘッダファイル内に cp932 でない文字が含まれていると変換できないのでエラーになっていました。

ちなみに、UTF-8 文字は bits/forward_list.h の 783 行目にあります。

$ grep -P -n "[^\x00-\x7F]" /usr/include/c++/7/bits/forward_list.h
783:      // 23.3.4.5 modifiers:

え、UTF-8 文字なんてない? いえ、よく見てください。 は fi という 2 文字ではなくて LATIN SMALL LIGATURE FI (\uFB01) という UTF-8 の 1 文字です。

推測ですが、実装したひとは non-ascii な文字を導入したつもりは全くなくて、pdf か web からコメントの文 23.3.4.5 modifiers をコピーしてきて混入したのではないかと思われます。

どうするべきか?

-finput-charset を指定するのはやめて、ソースコードを UTF-8 にしましょう。

STL に限らず、GitHub のかなり人気のライブラリ(例えば catch2 とか)でも同じ問題があり、-finput-charset を使う限り結構な頻度ででくわします。

9
3
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
9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?