6

重複の可能性:
誰でもこれらの未定義の動作を説明できますか (i = i++ + ++i 、 i = i++ など…)

#include<stdio.h>
#include<conio.h>

#define SQ(x) x*x

void main()
{
   int a1 , a2;
   int b1 , b2;

   a1 = 2;
   a2 = 2;

   b1 = 0;
   b2 = 0;

   b1 = SQ(a1++);
   b2 = SQ(++a2);

   printf("Frist = %d",b1);
   printf("Second = %d",b2);
}

コードの出力が何であるかを知っています。

#define が他のプログラムで機能するように、上記のコードで機能しないのはなぜですか?

4

9 に答える 9

16

同じ変数に対して複数の ++ 演算子を使用した式の結果は、正式には Cでは未定義の動作です。

于 2010-11-02T15:53:38.007 に答える
7

#defineは、マクロの各出現箇所をその展開で文字通り置き換えるためのプリプロセッサへの命令です。したがって、コード内の関連する行は、次のようにコンパイラに渡されます。

b1 = a1++ * a1++;
b2 = ++a2 * ++a2;

Sevaが述べているように、これらの表現は公式には定義されていません。しかし、おそらく最も賢明な読み方をとっても、それでも得られますb1 = 2 * 3;b2 = 3 * 4;両方とも、行の後に4に設定されますa1) 。a2

于 2010-11-02T15:55:24.620 に答える
3

SQの両方の使用は、シーケンスポイントごとに複数回a1とa2に割り当てられるため、未定義の動作を呼び出します。マクロへの割り当てや増分などの副作用のある式を渡さないでください。

于 2010-11-02T15:54:39.500 に答える
2

なぜなら、defineは式を置き換えるだけだからです。結果が得られます:

b1 = (a1++)*(a1++);
b2 = (++a2)*(++a2;

したがって、2回の増分が2回得られます。その結果、未定義の動作が発生します。

于 2010-11-02T15:54:30.073 に答える
2

おめでとう!この種のことにマクロを使用することがなぜ悪い考えなのかを発見したところです。原則として、関数を使用して実行できない場合にのみ、何かをマクロにします。この場合、SQ代わりに関数として簡単に実装できます。

int sq (int x)
{
    return x * x;
}
于 2010-11-02T16:04:10.007 に答える
1

マクロ内のオペランドを括弧で囲みます。

#define SQ(X) (X)*(X)

また、同じ割り当てでx++とxを操作しないようにしてください。未定義の動作につながる可能性があります。

乾杯!

于 2010-11-02T15:55:16.960 に答える
1

台詞

b1 = SQ(a1++);
b2 = SQ(++a2);

に展開

b1 = a1++ * a1++;
b2 = ++a2 * ++a2;

これは未定義の動作を呼び出します(オブジェクトの値はシーケンスポイント間で最大1回変更される可能性があります)。つまり、結果はすべて「正しい」と見なされます。

これが、この種のマクロの問題です。引数を1回評価する必要がありますが、拡張のために2回評価されます。

次のような表現で呼び出すことにも問題があります

x = SQ(a + b);

これはに拡張されます

x = a + b * a + b;

これはおそらくあなたが望んでいたものではありません。演算子の優先順位を維持するには、展開を次のようにラップする必要があります()

#define SQ(x) (x) * (x)
于 2010-11-02T15:57:08.357 に答える
0

プリプロセッサによって展開されるコードを見てください。

b1 = a1++ * a1++;
b2 = ++a2 * ++a2;

変数間にシーケンスポイントがない状態で変数を複数回変更しているため、これは未定義の動作です。

于 2010-11-02T15:55:45.033 に答える
0

あなたの質問が何であるかは本当にわかりませんが、予想される出力に問題がある可能性があります...#defineコードがコンパイルされる前に実行される「単純な」テキスト置換であることに注意してください。このテキスト置換は、スコープや構文の正しさを尊重しません。それは、あなたが言ったことと一致するものをすべて置き換えるだけです。あなたの場合、実際には "a++" の結果の 2 乗は作成されず、代わりに次のコードが生成されます: b1 = a++ * a++;

ここを見ると、「 C プログラミングに関する質問」を見ると、"a++ * a++" が正式に未定義の動作である理由について、いくつかの説明が表示されます。

于 2010-11-02T15:58:58.297 に答える