2016-07-24 7 views
-1

私の言うところのコードでは、出力は11 6 10であるべきですが、それは12 6 11です。 からとy=6のように3進演算子によって返されたk=xの値はi=11,j=6およびk=10です。なぜ出力が不一致であるのですか?以下のコードでマクロ展開はどのように機能しますか?

#include <stdio.h> 

#define MAX(x,y)(x)>(y)?(x):(y) 

int main() 
{ 
    int i=10,j=5,k=0; 
    k=MAX(i++,++j); 
    printf("%d %d %d",i,j,k); 
    return 0; 
} 
+1

動作が完全に定義されていても、間違っています。 –

+0

'k =(i ++)>(++ j)と比べて? (i ++):(++ j) 'これはマクロが展開するものです。 – dxiv

+2

あなたがThe International Obfuscated C Code Contestに参加しない限り、このようなコードを書くことはありません。 – kaitian521

答えて

2

膨張はに等しい:条件が評価されるようにインクリメントされ

k = (i++) > (++j) ? (i++) : (++j); 

両方ij(条件iの元の値をチェックするので、従ってi11j6なるなります。 j10 > 6のインクリメントされた値の場合、?の後のi++が評価されるため、k11 ssignedので、出力され、それがあるべきようiは、12

にインクリメントされます。未定義の動作がここにありません

12 6 11 

。条件が評価された後、完全なシーケンスポイントがあります。

注意が、あまりにも、それは完全な安全のために、マクロが展開囲む括弧の余分なセット持っている必要があります。そうしないと

#define MAX(x,y) ((x) > (y) ? (x) : (y)) 

を、あなたが得る奇数ボールの影響から:

int l = 7 * MAX(k, i) + 3; 

できます;期待どおりに機能しません。

+0

'(i ++)>(++ j)'これは、 'i'と' j'の両方が比較後にインクリメントされることを保証していますか? (そして '?'の前に) – artm

+0

はい。比較が完了し、疑問符の後のいずれかの用語が評価される前に、「i」と「j」の両方がインクリメントされます。 –

+0

このような場合、 '(++ i)>(++ j)と同じですか? (++ i):(++ j); '? – artm

1

出力が期待通りに機能します。マクロが展開されていることを理解する必要があり、入力パラメータがコピーされた場所のように機能しません。

上記のコードではMAXの定義は

#define MAX(x, y) (x)>(y)?(x):(y) 

あるので

k = MAX(i++, ++j) 

は二回

k = (i++)>(++j)?(i++):(++j) 

iはインクリメントます変数に展開されたとき、私= 10、J = 5。変数jは1回だけインクリメントされます。

したがって、最終的にi = 12およびj = 6であり、k = 11であるため、3進演算子の第2オペランドはポストインクリメントです。

gccを使用している場合は、.CファイルにCPP代わりのgccのを実行すると、あなたのための素敵なマクロを拡大します。

Jonathan Lefflerの安全性のためにマクロ内でより多くの括弧を使用するコメントとは別に、これらの意図しない結果からあなたを救うインライン関数の使用を検討することができます。インライン関数には型付き、値渡し、コード拡張の利点があります。

inline int max(int x, int y) { return x > y ? x : y; } 

詳細については、wikiを参照してください。

関連する問題