• ベストアンサー

マクロの展開(C言語)について

#define WRITE_test(TEST) \ do{ \ fprintf(stderr, "%s can't open\n", #TEST); \ }while(0); というマクロを書いた上で、ソースをコンパイルすると /**/ if (length_max/*LENGTH_buf_mpi*/ > length+strlen(buf_)) do{ fprintf(stderr, "%s can't open\n", "test"); }while(0); else if (length_max/*LENGTH_buf_mpi*/ > length+strlen(buf_)) do{ fprintf(stderr, "%s can't open\n", "test"); }while(0); else break; とある箇所にエラーなどは現れず /**/ if (length_max/*LENGTH_buf_mpi*/ > length+strlen(buf_)) WRITE_test(test); else if (length_max/*LENGTH_buf_mpi*/ > length+strlen(buf_)) WRITE_test(test); else break; とある箇所で、 「buf_.c:263: error: 構文解析エラー が "else" の前にあります」 というメッセージが現れます。263行とはひとつめのWRITE_test()がある箇所です。  マクロはテキストが置換、展開されるものと考えると、この結果に納得できないでおります。説明がつくでしょうか?  コンパイルはgentoo Linux上で/usr/bin/gcc-3.4.4によるものです。

質問者が選んだベストアンサー

  • ベストアンサー
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.2

★原因はセミコロンをマクロ関数につけているからだよ。 if (length_max/*LENGTH_buf_mpi*/ > length+strlen(buf_))  WRITE_test(test); else if (length_max/*LENGTH_buf_mpi*/ > length+strlen(buf_))  WRITE_test(test); else  break; ↑上記を展開します↓ if (length_max/*LENGTH_buf_mpi*/ > length+strlen(buf_))  do {   fprintf(stderr, "%s can't open\n", #TEST);  } while(0);; else if (length_max/*LENGTH_buf_mpi*/ > length+strlen(buf_))  do {   fprintf(stderr, "%s can't open\n", #TEST);  } while(0);; else  break; となりますよね。 すると『while(0);;』でセミコロンが2つになります。 それで if 文に{ }のブロックがありませんので、次のように解釈されます。 if ( … ) do { … } while(0); ; else if ( … ) do { … } while(0); ; else break 普通に考えて if ( … ) 次の1文 ; else break ↑ 『else』の前にセミコロンつけるとエラーになりますよ。 よって、 #define WRITE_test(TEST) \ do{ \ fprintf(stderr, "%s can't open\n", #TEST); \ }while(0) ←セミコロンを取ればよい。 その他 ・このような場合の為に if、else の{ }のブロックは省略しない方がよいのです。  もしも、if、else に{ }のブロックをつけて記述すれば、マクロにセミコロンが  あっても正しく処理されます。 ・以上。マクロ関数にセミコロンをつける場合は注意して下さい。

GT-
質問者

お礼

 一行目でヴィヴィッドに説明が伝わりました。ありがとうございます。たまたまこれまでelse以下をつけてこなかったので気づきませんでした。  if, elseの{}を省略しないことにするのはよさそうですけれど、この場合マクロのラスト、while(0)の後ろにセミコロンをつけない形にしておいて、ソースの中でマクロを使用する際には一般の関数に似せてセミコロンをつけることにするのがいいかなと考えました。  ご丁寧な説明、ありがとうございました。

その他の回答 (4)

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.5

★もしかして、複数の処理を1文で記述できるように do-while を使っているとか。 ・昔、持っていた本に載っていたような気がした。  それで『do { 複数の処理 } while(0)』とマクロで定義しているのね。  私はif、else に{ }文字を省略しないのでマクロ関数に{ }文字のブロックで  囲んで定義することがあります。    #define MacroName( a, b )\  {\   宣言など\   \   /* コメント */\   処理1\   処理2\    :   処理n\  }\ ←私は、ここにも¥文字を付ける  ←上に¥を付けているので必ず1行以上空行を空けて定義する。 その他: ・ここでは連続するタブ文字とスペースが1個になるので全角の空白を使って  インデントなどを表現できます。 ・以上。参考に!

GT-
質問者

お礼

 いくつか流儀があるのですね。  自分が参考になったところで大きく共通しているのは、{ }(do()while(0)を含めて)をつかうことでマクロの中で関数ライクに複数の処理を行える点、{ }内で各種の宣言が可能である点です。そこそこ本を読みながらプログラムを書いているつもりなのですけれど、このあたりのことは記憶に残る箇所に明らかにはされていませんでした。  このあたりをもっと早く知っていたら、デバッグの作業も数値計算上の確認もたいへん楽になっていたのに。ここのところで一番ためになった箇所です。  全角の空白をつかうことには違和感を感じるのですけれど、この場でこだわることはないですね。こちらもたいへん参考になりました。ありがとうございました。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.4

その (do ... while (0) という) 形のマクロを自分で思い付いたんだったらすごいけど.... その形のマクロでは最後にセミコロンを付けないのが普通. まあ, 1行なのに do ... while(0) ってのも冗長だけど.

GT-
質問者

お礼

 見かけたことがあって、真似てみました。セミコロンをたぶんそこではつけていなかったのだと思います。細かいところまで把握し切れていなかったのですね。  こういうコツは、みなさんどこで習得するのでしょう?はじめて目にしたときはびっくりしました。おもに買いだめしたC言語の本とweb上の情報をもとに試行錯誤しているのですけれど、手元の資料にはこういう工夫は載っていません。  回答を締め切ったつもりでできていなかったのですけれど、この件を書き込んでしまうのでもう少し締め切るのを延長させてください。  1行であるのは、書いたマクロを本来の形からどんどん削っていって、それでもエラーが残って悩んでしまった結果です。 # トピックを外れていろいろ書くのはよろしくないとは思いますけれど、新しく書き込むほどのことはなさそうなのでもうひとつ。  投稿した後の画面では半角の空白やタブが消えてしまっていました。これにはどう対処すればよろしいのでしょうか?

  • MrBan
  • ベストアンサー率53% (331/615)
回答No.3

# 単純にコンパイルエラーが出てるだけで、表示行数の話ではないのね…orz # 完全に読み違えてました。ごめんなさい。

GT-
質問者

お礼

 いえ、こちらも不慣れなもので、きちんと伝わる形で質問できていなかったように思います。  はじめて知る話も紹介いただいたわけで、調べて勉強にします。ありがとうございました。

  • MrBan
  • ベストアンサー率53% (331/615)
回答No.1

gccの実装/仕様を確認したわけではないので憶測ですが…、 そのエラーメッセージは__LINE__に基づいてたり、 複数行に同じ__LINE__が割り当てられてたりはしないのでしょうか。

関連するQ&A