トップページ⇒tech
265コメント72KB

プリプロセッサについて熱く語るスレ。

■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさんNGNG
さぁ語れ。
0153デフォルトの名無しさんNGNG
>>152
レスサンクス。お陰で理解できた。
>IGNORE_X→IGNOREでxを評価してCAUSE_ERROR以降を評価するから。
どうもこの通りみたいで、仮引数実引数置換のときにxを展開するらしい。
ちなみに、IFに関してはちょっとしたトリックでこの問題を回避できるようだ。

#include ">>151"

#define CAT(a, b) a ## b
#define LAZY_IF(c) CAT(LAZY_IF_, c)
#define LAZY_IF_0(x, y) y EAT(#x)
#define LAZY_IF_1(x, y) x EAT(#y)

#define RESULT ok
#define COND 1

LAZY_IF(COND)(RESULT, CAUSE_ERROR) /* エラーを起こすことなくokに展開される */
0154デフォルトの名無しさんNGNG
昔からモトローラのアドレシングモード表記が大嫌いで、
H8使う羽目になったときザイログ式で表記するために
プリプロセッサ作ったなぁ。
0155デフォルトの名無しさんNGNG
保守上げ
0156デフォルトの名無しさんNGNG
遅レスだが、
>>151
C99が使えるなら、
#define IGNORE_X(x, pm) IGNORE(pm ## x)
IGNORE_X(CAUSE_ERROR,)
でいけるぞ。
0157デフォルトの名無しさんNGNG
///*
hogehoge();
hoge();
foo();
//*/

こんな感じで、CのコメントをC++のコメントでコメントアウトして使っている。
先頭の「///*」を「/*」に変えると、一気にコメントアウトされて便利。
VC++でしか動作確認とってないから、他だとどうなるか知らんけど
0158デフォルトの名無しさんNGNG
>>157
#if 0
hogehoge();
hoge();
foo();
#endif

にして、0 と
0159デフォルトの名無しさんNGNG
途中で書き込んでもた。

>>158 訂正

#if 0
hogehoge();
hoge();
foo();
#endif

にして、0 と 1 を書き換えれば環境依存もないはずだが。
0160デフォルトの名無しさんNGNG
CのマクロはLISPの様にインライン関数にも使えないし、
評価の制御も無理で、常にシンボルの衝突の危険を強いられる。
解決したとしてもexpression中にcompound-statementは書けない。
せめてこれぐらいの自由度が欲しい。

#define macro_double(x) \
 #let y = gensym() in \
 { int y = x; return y * y; }

f(x){printf("f(%d\n)\n",x);return x;}
main() { printf("%d\n", macro_double(f(1))); }

↓macro-expand

main() {
 printf("%d\n", {int g1 = f(1); return g1 * g1; }); // error
}
0161デフォルトの名無しさんNGNG
>>160
Cでは内側の名前は外側の名前を隠すから、シンボルの衝突は問題ないと思われる。
どちらにしてもインライン関数としてマクロを使うのは無理があるだろうが。
標準にもinlineが導入されたし、GCCにはマクロから値を返すための独自拡張があるくらいだからな。

ところでお前ら、Cプリプロセッサで直接的に再帰を行うscan recursionてどうよ。
ttp://aspn.activestate.com/ASPN/Mail/Message/boost/1609570
古い話題スマソ
0162デフォルトの名無しさんNGNG
アホかと
0163デフォルトの名無しさんNGNG
>>161
>Cでは内側の名前は外側の名前を隠すから、シンボルの衝突は問題ないと思われる
# define swap_int(a, b) do{int temp = a; a = b; b = temp;}while(0)
int x, temp;
swap_int(temp, x);
こんなのは悲惨なことになるぞ。
0164デフォルトの名無しさんNGNG
>>163
cでは

int foo = foo;

なんて訳の分からない書き方が許されてしまう罠。
GCC は昔これを許さない構文を導入したい、とか言ってたけど。
0165164NGNG
間違ってあげてしまいました。
吊って来ます。
0166デフォルトの名無しさんNGNG
>>157
//* ←のスラッシュは2つでもいい。
hogehoge();
hoge();
foo();
//*/
0167デフォルトの名無しさんNGNG
// による /* の無効化は C99、C++98 のいずれでも有効みたい
0168デフォルトの名無しさんNGNG
別にC99コメントに頼らなくても
/*
hogehoge();
hoge();
foo();
/**/
でいいんじゃないか?
0169デフォルトの名無しさんNGNG
>>168
確かにそうやってるソースを見たことがある。
…でもネストが崩れてるので落ち着かないんだよな。
つか、ソースのコメントアウトには #if を使えと言いたい。
0170デフォルトの名無しさんNGNG
こんなの見つけた
http://www.pp.iij4u.or.jp/~nabe/c/c_lang/clang07.html
0171デフォルトの名無しさんNGNG
ていうか
http://www.sun-inet.or.jp/%7Eyaneurao/intensive/tips2.html
ここのTips67ではダメなのか?
#if 0 〜 #endifよりも/* */の色分けに対応しているエディタの方が多いから
C++とか // 形式のコメントが使えるならこっちの方が見やすいかと思ってるけど。

ところでコメントってプリプロセッサの仕事だっけ?
コンパイラの仕事じゃなくて?
0172デフォルトの名無しさんNGNG
>>171
>ところでコメントってプリプロセッサの仕事だっけ?
コメントはマクロ展開よりも前に処理されることになっている。
コメント全体を一種の空白とみなせばプリプロセス後まで残すこともできるだろうが。

どっちにしても、コメントの話題がすれ違いならこのスレは終わりだな。
0173デフォルトの名無しさんNGNG
あ、いや済まん。純粋に疑問だっただけだ。
そうかコメントはマクロ展開より前に処理なんだな。
まあ別にプリプロセッサとコンパイラと明確に分ける必要もないんだろうが…

とりあえずgccで-Eオプションをつけた出力だとコメントはすでに消えていた。
詳しくはわからんけど、コメントの話題がスレ違いということはなさげ。
0174デフォルトの名無しさんNGNG
>>171
確かに色分け考えると見やすいかもしれんが、個人的にはすっきりしない。
通常の注釈は //、ブロックの無効化は /*, */ という形ではっきり分かれてるならいいんだけど、
必ずしもそうではないし。新しい記号だと思えばいいのかもしれんが。
注釈は //, /*, */、 ブロックの無効化は #if, #endif という規約だと、意味づけと表記を対応した形で
分けられるんでこっちの方が好きなのよ。
0175デフォルトの名無しさんNGNG
#define BIN(x) ( \
(((x) / 1 & 1) << 0) + \
(((x) / 10 & 1) << 1) + \
(((x) / 100 & 1) << 2) + \
(((x) / 1000 & 1) << 3) + \
(((x) / 10000 & 1) << 4) + \
(((x) / 100000 & 1) << 5) + \
(((x) / 1000000 & 1) << 6) + \
(((x) / 10000000 & 1) << 7))
こんなのだめ?
0176デフォルトの名無しさんNGNG
>>175
すまない。意図かあるいは使用例あたりを示してはくれまいか。
0177デフォルトの名無しさんNGNG
>>176 おそらく二進定数だろう
0178デフォルトの名無しさんNGNG
なるほどこういうことか
printf("%d\n", BIN(1111)); // 15
printf("%d\n", BIN(1110)); // 14
printf("%d\n", BIN(1101)); // 13
printf("%d\n", BIN(1100)); // 12
printf("%d\n", BIN(1011)); // 11
printf("%d\n", BIN(1010)); // 10
printf("%d\n", BIN(1001)); // 9
printf("%d\n", BIN(1000)); // 8

だがこの調子で行くと7以下は微妙だな…
printf("%d\n", BIN(0111)); // 3
printf("%d\n", BIN(0110)); // 2
printf("%d\n", BIN(0101)); // 1
printf("%d\n", BIN(0100)); // 0
printf("%d\n", BIN(0011)); // 1
printf("%d\n", BIN(0010)); // 0
printf("%d\n", BIN(0001)); // 1
printf("%d\n", BIN(0000)); // 0

Prefix 0 はCの仕様として8進定数になってしまうから
桁を揃えようとすると上手くいかなくなる…
もちろんBIN( 111)とやればうまく7になるんだが、
二進で定数書きたいときは普通桁そろえたいよな…
0179デフォルトの名無しさんNGNG
こんなの見た事が。
enum {
b0, b1
};
enum {
b00, b01, b10, b11
};
以下似たような奴の羅列。
0180デフォルトの名無しさんNGNG
強引に8進定数にすればいいじゃないか
#define BIN(x) BIN_I(0 ## x ## u) /* uは気休め */
#define BIN_I(x) ( \
(x >> 0 & 1) << 0 | \
(x >> 3 & 1) << 1 | \
(x >> 6 & 1) << 2 | \
(x >> 9 & 1) << 3)

int i[BIN(1111)]; /* 15 */
int j[BIN(0010)]; /* 2 */
0181175NGNG
>>178,180
�dクス
授業中に考えたんで8進定数の存在忘れてました。
180の使わせてもらいます。
0182デフォルトの名無しさんNGNG
ageっと
0183デフォルトの名無しさんNGNG
#define NUM 100
#NANNTOKA (perl -e "printf('%x', (NUM))")

とかしたらNANNTOKAがperlからの標準出力を
ソースに埋め込むみたいな、そんな機能は
ありませんか?
0184デフォルトの名無しさんNGNG
そんな機能はありません。
0185デフォルトの名無しさんNGNG
>>183
#if 0
#!/usr/bin/perl
while <__DATA__> {
s/hogehoge/mosamosa/
}

__DATA__
#endif

perlはよく知らんけど、やろうと思えばこんな感じではできるんじゃない?
コンパイルする前にper;に読ませる必要があるだろうけど。
0186デフォルトの名無しさんNGNG
プログラムの標準出力をファイルにマップするようなファイルシステムがあれば良いんだが、
unixの「名前つきパイプ」って使えたっけ?
0187デフォルトの名無しさんNGNG
>>186
http://forum.nifty.com/fdelphi/samples/01273.html
0188デフォルトの名無しさんNGNG
183からちょっと発想を拝借して

#include "|perl code.pl"

こんな感じでスクリプトの実行結果を取り込めないかなー。
cygwinではだめですた。
0189デフォルトの名無しさんNGNG
erbでも使えば
0190デフォルトの名無しさんNGNG
>183,188
makeで十分ですよ。分かって下さいよ。
0191デフォルトの名無しさんNGNG
>>190
make でどうやんのか教えろ!
0192デフォルトの名無しさんNGNG
こんな感じ?

(Makefile)
all: dynamic.c dynamic.h
  gcc dynamic.c
dynamic.h: code.pl
  perl code.pl > dynamic.h

(code.pl)
print <<"CODE";
#include <stdio.h>
int do_dynamic() { return puts(":)"); }
CODE

(dynamic.c)
#include "dynamic.h" /* for do_dynamic() */
int main(int ac, char *av[]) { return do_dynamic(); }
0193デフォルトの名無しさんNGNG
>>192
ヘッダ中に
#define NUM 100
とあって、コード中でNUMを外部コマンドに
食わせて何か出力を得たいような場合はどうやんの?
基本的にパラメータはヘッダで定義。これは譲れない。
0194デフォルトの名無しさんNGNG
>>193
cpp -dMの結果でも解析汁
0195デフォルトの名無しさんNGNG
>193
sed

つーかそういうdefineは、コマンドラインから与えるのが良識的だと思うが。
0196デフォルトの名無しさんNGNG
プリプロセッサのすれなんだからプリプロセッサでコード生成しろよ
0197デフォルトの名無しさんNGNG
メンバ変数のメンバ関数を外側のクラスメンバにエクスポートするような
マクロを以下のように定義しましたが、コンパイルがとおりません。何処が問題でしょうか?

#define GET_FUNCTION(func,type,obj) type Get##func(){return obj##.Get##func();}
#define SET_FUNCTION(func,type,obj) void Set##func( type newVal ){ obj##.Set##func( newVal ); }
#define DEF_FUNCTION(func,type,obj) GET_FUNCTION(func,type,obj)\
SET_FUNCTION(func,type,obj)

例)
DEF_FUNCTION( TransitionType, int, m_aaa )

もちろんm_aaaには、GetTransitionTypeというメンバ関数があります

開発環境 VC++6.0 sp6
エラー
error C2061: 構文エラー : 識別子 'TransitionType' がシンタックスエラーを起こしました。
0198デフォルトの名無しさんNGNG
age
0199デフォルトの名無しさんNGNG
>>197
'\'が行末にないからじゃね?
同じvc6sp6で通ったよ?
シンボルの未定義エラーはでたけど、構文エラーにはならなかった。
0200デフォルトの名無しさんNGNG
それとさ、/Pオプションでマクロの展開内容が*.iファイルに出力されるから
覚えとけ。
0201デフォルトの名無しさんNGNG
##はトークン結合。
.は独立したトークンだから、結合してはいけない。

#define GET_FUNCTION(func,type,obj) type Get##func(){return obj.Get##func();}
#define SET_FUNCTION(func,type,obj) void Set##func( type newVal ){ obj.Set##func( newVal ); }
#define DEF_FUNCTION(func,type,obj) GET_FUNCTION(func,type,obj)\
SET_FUNCTION(func,type,obj)
0202デフォルトの名無しさんNGNG
>>197
obj##. の ## は要らなさそう。
0203デフォルトの名無しさんNGNG
ついでに、/Pオプションでの出力結果

int GetTransitionType(){return m_aaa.GetTransitionType();}void SetTransitionType( int newVal ){ m_aaa.SetTransitionType( newVal ); }
0204197NGNG
>>198-203
色々有難う御座いました
全然違うところでミスってましたTT

/P
は試してみたんですが、展開されていなかったので???と思ったんです。
そうしたら

#ifndef ... #endif

で見事に、定義がとばされていましたw
0205デフォルトの名無しさんNGNG
シネ
0206デフォルトの名無しさんNGNG
特定の言語に依存しないPP
ってありませんか?
0207デフォルトの名無しさんNGNG
m4とか
0208デフォルトの名無しさんNGNG
というか、gccではc++からしてPP扱い。
0209デフォルトの名無しさんNGNG
VisualStudioで、下に示す感じで
#include "stdafx.h" を制御してやろうと思ったのに
"fatal error C1020: 予期しない #endif です。"
というメッセージが出てコンパイルが通りません。なぜでしょう。

目的は、VC とそれ以外のコンパイラで動くソースを作りたいです。

#ifdef WIN32
#include "stdafx.h"
#endif

#include <stdio.h>

int _tmain(int argc, _TCHAR* argv[])
{
printf( "hello, world\n" );
getchar();
return 0;
}

//-----stdafx.h-----------------
// #pragma once
//
// #define WIN32_LEAN_AND_MEAN
// #include <stdio.h>
// #include <tchar.h>
//--------------------------------
0210デフォルトの名無しさんNGNG
>>209
ほんとだ、プリコンパイル済みヘッダの場合だけエラーになるね。
VC のバグじゃないかな。
対策としては、stdafx.h 内で #ifdef WIN32 したらどうかな。
0211デフォルトの名無しさんNGNG
>>163
> # define swap_int(a, b) do{int temp = a; a = b; b = temp;}while(0)

こういうのって、

# define swap_int(a, b) { int temp = a; a = b; b = temp; }

だけじゃだめなの?
なんでわざわざ do 文にするの?
0212730NGNG
>>209
VCは #include "stdafx.h" を発見するまで読み飛ばすようになってる。
たとえば
#include "hoge"
#include "stdafx.h"
と書いても、 "hoge" は無視される。
0213デフォルトの名無しさんNGNG
730 は名前消し忘れ

>>211
if (mememe) swap_int(a,b);
else momomo;
0214デフォルトの名無しさんNGNG
>>213
ありがとう!そういうことでしたか。
0215デフォルトの名無しさんNGNG
#define STRDUP_HEADER <string.h>
#include STRDUP_HEADER

↑こんな使い方って問題あります?
VC ではとおりますけど、実際にこういう使われ方を見たことがない。
0216デフォルトの名無しさんNGNG
>>215
問題ない。Boost.Preprocessorでは多用されている。
0217デフォルトの名無しさんNGNG
>>215
問題ない。少なくとも C++ では、規格中の 16.2 -4- に記述がある。
STLport のコンフィグで使われてるのを見たことがある。
0218デフォルトの名無しさんNGNG
__LINE__とかの展開ってプリプロセッサじゃなくてコンパイラが行うっていう理解でいいんでしょうか?
VC6++のASSERTマクロの実装みたら中で__LINE__してあったもので
0219デフォルトの名無しさんNGNG
>>218
いや、プリプロセッサだろ。
「__LINE__してある」って何?それが__LINE__の展開をコンパイラが行っている根拠になるの?
0220デフォルトの名無しさんNGNG
>>218
'#define' の右側に現れたトークン列はその場では展開されない。たとえば、
# define A result
# define X A
# undef A

X /* 'result' ではなく 'A'に展開される。 */

__LINE__の扱いは通常のマクロと同じ。
/* hoge.h line 7 */
# define MACRO __LINE__

/* hoge.c line 133 */
MACRO
このとき、MACROは次のように展開される。
MACRO
-> __LINE__
-> 133
0221デフォルトの名無しさんNGNG
>>220
218じゃないけど、勉強になった
0222デフォルトの名無しさんNGNG
>>219
VCにプリプロセッサ展開オプションをつけたことはないのですか?
荒れるげいいんになるので、解らないなら書き込まないでください。
0223デフォルトの名無しさんNGNG
プリプロセッサの展開をトレース実行してくれるツールってないでしょうかねぇ。
VC のデバッガみたいに、ブレークポイントを設定したり、ステップ展開したり
できるといいと思わないですか?
0224デフォルトの名無しさんNGNG
>>223
トレース実行じゃないけど、waveなら、
#pragma wave trace(enable)
すれば、マクロ展開の様子をトレースして結果をファイルに出力できる。
0225デフォルトの名無しさんNGNG
waveは
ttp://spirit.sourceforge.net/index.php?doc=docs/wave_v1_0/index.html
ね。
0226デフォルトの名無しさんNGNG
>>210 >>212
209です.

そういうことでしたか、どうもありがとうございました。
今はMacintoshから書き込んでいるので、
プリコンパイルヘッダの件については後でやってみます。それではBYE!
0227219NGNG
>>222
ごめん。意味わからない。
0228デフォルトの名無しさんNGNG
お前ら!おもしろそうなものができてますよ

Chaos Preprocessor
http://sourceforge.net/projects/chaos-pp/
0229デフォルトの名無しさんNGNG
>>228
これどんなことできるの?
誰か分かりやすく教えて君。
0230デフォルトの名無しさんNGNG
0231デフォルトの名無しさんNGNG
>>229
chaos-ppとorder-ppがあって、どっちも基本的には
プリプロセッサを使ってコード生成をするためのライブラリ。

chaos-ppの方はboost::preprocessorの方向性を推し進めたもので、
無限精度整数とか文字列とかラムダ式とかが扱えるらしい。

order-ppは、プリプロセッサの上で動く関数型言語のインタプリタの実装で、
ユーザーはこの言語を使ってコードジェネレータを書く。たとえば
http://cvs.sourceforge.net/viewcvs.py/chaos-pp/order-pp/example/average.h?view=markup
には、この言語(8がたくさん出て来る奴)を使って実装された
平均を計算するコードを生成するマクロがある。
0232デフォルトの名無しさんNGNG
ありがとう。
だけどあんまり便利そうじゃないねぇ。。。
0233デフォルトの名無しさんNGNG
出力コードが想像できないと
デバッグ大変そうだな
0234デフォルトの名無しさんNGNG
面白ければそれでよし。実用性なんて2の次
0235デフォルトの名無しさんNGNG
あ、でもプリプロセッサであんまり沢山処理するよりは、
BOOST_PPみたいにリストの基本的な操作に限定して、
テンプレートメタプログラミングの方であれこれ
やるのが今風のような。
BOOST_PPは今から新たに機能拡張していくつもりあるのかな?
0236デフォルトの名無しさんNGNG
>>235
C99に対応したBOOST_PPなんかあったら面白いかも
0237デフォルトの名無しさんNGNG
プリプロセッサという考え方は、
未成熟な言語を補助するための苦肉の策にすぎない。
0238デフォルトの名無しさんNGNG
>>235
boost::preprocessorの作者は二人で、その二人が
orderとchaosを一つずつ開発してるっぽい。
もうboost::preprocessorは飽きたんじゃないかな。
0239デフォルトの名無しさんNGNG
PHPとかePerlとか、埋め込み型スクリプトをプリプロセッサ代わりに使うのって面白そうな気もするんだが、おまいらどうおもう?
0240デフォルトの名無しさん05/02/02 18:16:59
ほしゅさげ
0241デフォルトの名無しさん05/03/06 16:32:37
age
0242デフォルトの名無しさん2005/04/16(土) 11:58:11
waveのpragmaに>>183みたいなのがあるな。
0243デフォルトの名無しさん2005/05/17(火) 22:57:20
#define AAA 999
が定義してあって

int a = AAA.AAA
が置き換えられるとする。
結果がコンパイラによって違うんだけど、どっちが規格に準拠してるのかな?

・cl.exe(MSのC/C++コンパイラ)の場合
int a = 100.AAA

・gccの場合
int a = 100 . 100
0244デフォルトの名無しさん2005/05/18(水) 00:12:31
>>243
トークンの生成(tokenization)はマクロ置換の前だから、gccが正しい。
VCのプリプロセッサはうんこ。
02452442005/05/18(水) 00:23:17
よく見てなかった。どっちもだめだな。
0246デフォルトの名無しさん2005/05/18(水) 00:44:56
>>243 なんで展開結果に999が現れないんだ?
02472432005/05/18(水) 02:24:50
>>246
すいません間違えてました。正しくはこうです。

#define AAA 999
int a = AAA.AAA

・cl.exe(MSのC/C++コンパイラ)の場合
int a = 999.AAA

・gccの場合
int a = 999 . 999
0248デフォルトの名無しさん2005/06/19(日) 17:15:15
死んじゃうよ
0249デフォルトの名無しさん2005/07/23(土) 21:46:10
マクロ内部でランダムなシンボルをどうにかして
使用する方法はないでしょうか?

#define HOGE int <ランダムなシンボル>

みたいな。
0250デフォルトの名無しさん2005/07/23(土) 21:48:04
ついでに保守
0251デフォルトの名無しさん2005/07/23(土) 21:52:50
なんに使うんだよ。
他のスクリプトで自動生成すれば?
0252デフォルトの名無しさん2005/07/23(土) 21:56:18
>>251
おなじブロックで2度呼ばれたり、ネストして呼ばれたりすると
シンボルがかぶってしまうからです。
■ このスレッドは過去ログ倉庫に格納されています