エラーを引き起こすコメント行
とあるC言語のプログラムを Windows 上の Visual Studio 2008 で編集・作成し、完成したソースコードを Linux マシンにコピーし gcc でコンパイルしてデータ処理を実行という流れで作業を行っていました。
その際に、ある全角文字を含むコメント行が存在するとエラーが生じるという現象に遭遇しました。
このエラーを再現するプログラムは以下のようなものです。
#include <stdio.h> int main(void) { int n = 10; // n の値により分岐可能 if(n > 5){ printf("Large\n"); }else{ printf("Small\n"); } return 0; }
このソースコードは、Visual Studio上では何の問題もなくコンパイル、実行できます。
しかしながら、Linux の gcc によりコンパイルを行うと
main.c:10: error: expected identifier or ‘(’ before ‘else’ main.c:13: error: expected identifier or ‘(’ before ‘return’ main.c:14: error: expected identifier or ‘(’ before ‘}’ token
というエラーが出力されてしまい、コンパイルに失敗します。
そして、このプログラムの7行目の「// n の値により分岐可能」というコメント行を削除すると、Linux gcc でもこのエラーは解消され、コンパイル実行が可能となりました。
原因は2バイト目が \ になってしまう「Shift-JISのダメ文字」でした
この原因を探るためにバイナリエディタでソースコードを調べてみたところ、コメント行の最後に「\」(バックスラッシュ、または円マーク)に相当する文字コードが存在していました。
C言語では行末に \ が存在すると、その行の改行が無視されるということを思い出し、試しに最後の「能」の文字を削除したところ、Linux の gcc でも問題なくコンパイルに成功しました。
私が使っている環境での Visual Studio 2008 は、作成したプログラムのソースコードを Shift-JIS で保存するようになっています。
そして、「能」のShift-JISコードを調べると「94 5C」であり、2文字目は確かに半角文字「\」の文字コード 5C になっていました。
Shift-JIS には「能」のように2バイト目が \ 記号と同じバイト列になっており、いろいろと問題を引き起こす文字があると以下のサイトに説明されています。
まさにこれが、今回の問題を引き起こしていました。
この問題の回避は、Shift-JIS以外の文字コードを使う、あるいはコメントの最後の文字として「ダメ文字」以外を使うことで可能です。
このコメント行末の \ については、コンパイラによって単に \ を無視するのか(Visual Studio の場合)、あるいは \ を適用して次の行もコメントとして扱ってしまうのか(Linux gcc の場合)で挙動が分かれているようです。
「なぜか消すと動かないコメント」ネタも再現可能
プログラミング世界で時々聞くネタとして // このコメントを消すと動かないので消しちゃダメ といった摩訶不思議なコメントが書かれているプログラムがあるというネタがあります。
このネタは以下のソースコードを Shift-JIS で保存して、Linux gcc でコンパイルすることで再現可能です。
#include <stdio.h> int main(void) { int n = 10; // n の値により分岐可能 // この行のコメントを消すと動かないので、消しちゃダメ! if(n > 5){ printf("Large\n"); }else{ printf("Small\n"); } return 0; }
このソースコードでは // n の値により分岐可能 の行末の \ により次の行がコメントアウトされますが、次の行に// この行のコメントを消すと動かないので、消しちゃダメ! というコメントがあるおかげでこの「Shift-JISのダメ文字」の問題を回避できています。
そして、このコメントを消してしまうと、次の if(n > 5) { の行がコメント扱いされてしまい、コンパイルが通らなくなります。
それにしても発見に手こずり、原因を見つけるのも厄介なエラーでした・・・。