2014年08月27日

C/C++プリプロセッサの挙動の違い(/ ## /編)

マニアックなネタが続いて申し訳ありません。またプリプロセッサの話です。

前回:C/C++プリプロセッサの挙動の違い(defined編)
前々回:米Facebook社のC/C++プリプロセッサWarpをWindows環境でビルド

Warp の挙動を調べていて、以下のような、マクロ展開後にコメントが生成されるようなコードが通らない事に気が付きました。
(元は MinGW GCC の x86_64-gdcproject-mingw32/x86_64-gdcproject-mingw32/sysroot/mingw/include/wtypes.h ヘッダ)
$ cat gen_cpp_comment.c
#define _VARIANT_BOOL /##/

$ ./warp.exe --stdout gen_cpp_comment.c
# 1 "gen_cpp_comment.c"
# 1 "i:\test\warp//"
# 1 "<command-line>"
# 1 "gen_cpp_comment.c"
gen_cpp_comment.c(2) : ## cannot appear at end of macro text


実はこれ自体は Warp のバグ※なのですが、GNU cpp (GCC) と VC++ の間でも挙動が違いました。

※ skipWhitespace() というテンプレート関数の中で、'*' や '/' が 1 文字の場合に取りこぼしてしまっているようです。(そのため、最後の '/' がスキップされ「マクロ文字列の最後で ## は使用できない」とエラーになっています。)どうやら Warp は D 言語の InputRange という抽象的な構造のテンプレートで全体が記述されているので、入力ストリームの 1 文字先読みが困難(InputRange に可能な操作は empty/front/popFront() のみ)なため、トリッキーなコードになっているのがエンバグの原因に思えます。

GCC 4.9.0 では、定義自体は通りますが(そのため wtype.h ヘッダは問題無く使用できる)、実際に識別子を使用するとエラーになります。
$ cat gen_cpp_comment.c
#define _VARIANT_BOOL /##/

_VARIANT_BOOL

$ gcc -E gen_cpp_comment.c
# 1 "gen_cpp_comment.c"
# 1 ""
# 1 ""
# 1 "gen_cpp_comment.c"


gen_cpp_comment.c:1:23: error: pasting "/" and "/" does not give a valid preprocessing token
 #define _VARIANT_BOOL /##/
                       ^
gen_cpp_comment.c:3:1: note: in expansion of macro '_VARIANT_BOOL'
 _VARIANT_BOOL
 ^
/ /
VC++ では通ります。
>cl /E gen_cpp_comment.c
Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

gen_cpp_comment.c
#line 1 "gen_cpp_comment.c"
いずれにせよ避けるべき悪い書き方なのですが、このようなコメントの生成が valid なのかどうかは、ちょっと明確にはわかりませんでした。
N1256(C99 final draft)の 6.4.9 Comments には、根拠はちょっとわからなかったのですが、
http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf
#define glue(x,y) x##y
glue(/,/) k(); // syntax error, not comment
という近い例があり、また、6.10.3.3 The ## operator に
If the result is not a valid preprocessing token, the behavior is undefined.
とありますが、// がプリプロセッサのトークンとして valid なのかどうかがよくわかりませんでした。
もし詳しい方がおられましたら、ご教示いただければ幸いです。

関連しそうな URL: stackoverflow: Does the C preprocessor strip comments or expand macros first?

トラックバックURL

コメントする

名前
URL
 
  絵文字
 
 
記事検索
最新コメント
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード