-3

だから私はこの質問で立ち往生しています。

int i=5,a;
a=++i + i++ + ++i + i++ - --i;
printf("%d",a);

私によると、「a」は20である必要があります。a= 6 + 6 + 8-8しかし、実行時に答えは18であることがわかりました。何が間違っているのでしょうか。ステップバイステップの説明が役立ちます。

4

5 に答える 5

3

これについては、http: //blog.susam.in/2010/05/sequence-points.htmlのブログ投稿で詳しく説明しています。

その一部を抜粋して掲載しています。

C プログラミング フォーラムでは、特定の種類の質問が何度も寄せられます。フォーラムで経験豊富なプログラマーをいらいらさせるような質問については、2 つのことがあります。まず、この種の質問は非常に一般的であるため、同様の質問が回答されている別のスレッドへのリンクを投稿することになったとしても、多くの人は回答した​​くありません。第二に、さらに重要なことは、誰かが質問に正しい答えを提供しようとしても、それを無視して間違った答えでスレッドを埋める他の多くの人がいるということです.

質問には通常、このようなコードの出力を見つけることが含まれます。

#include <stdio.h>

int main()
{
    int i = 5;
    printf("%d %d %d\n", i, i--, ++i);
    return 0;
}

出力は、gcc でコンパイルすると 5 6 5 になり、Microsoft Visual Studio に付属の Microsoft C/C++ コンパイラでコンパイルすると 6 6 6 になります。

このような C プログラムの動作は未定義です。ステートメントで printf("%d %d %d\n", i, i--, ++i); および a += a++ + a++;、セミコロンが唯一のシーケンス ポイントです。C は、特定の式のすべての副作用が、プログラム内の次のシーケンス ポイントまでに完了することを保証します。次のシーケンス ポイントの前に、互いに影響を与える副作用を持つ 2 つ以上の操作が発生した場合、動作は未定義です。このようなコードは、異なるコンパイラでコンパイルすると、異なる動作をする場合があります。

ISO/IEC 規格の関連セクションを引用する前に、K&R から引用させてください。本のセクション 2.12 (評価の優先順位と順序) で、著者は次のように書いています。

C, like most languages, does not specify the order in which the

演算子のオペランドが評価されます。(例外は &&、||、?:、および ',' です。) たとえば、次のようなステートメントでは、

x = f() + g();

f may be evaluated before g or vice versa; thus if either f or g

もう一方が依存する変数を変更すると、x は評価の順序に依存する可能性があります。特定の順序を確保するために、中間結果を一時変数に格納できます。

このセクションでは、もう 1 つの例を示します。

One unhappy situation is typified by the statement

a[i] = i++;

The question is whether the subscript is the old value of i or the

新着。コンパイラはこれをさまざまな方法で解釈し、その解釈に応じてさまざまな回答を生成できます。

これについて詳しく知りたい場合は、ISO/IEC 9899 C 規格をダウンロードし、付録 C – シーケンス ポイントの 438 ページを参照してください。すべてのシーケンス ポイントを一覧表示します。; その一つです。+ および ++ 演算子はシーケンス ポイントではありません。

次に、セクション 5.1.2.3 (プログラムの実行) のポイント 2 をお読みください。

Accessing a volatile object, modifying an object, modifying a

ファイル、またはこれらの操作のいずれかを行う関数の呼び出しはすべて副作用であり、11) 実行環境の状態の変化です。式の評価により、副作用が生じる場合があります。シーケンスポイントと呼ばれる実行シーケンスの特定のポイントでは、以前の評価のすべての副作用が完了し、後続の評価の副作用は発生していません。(シーケンスポイントの要約は附属書Cに記載されています。)

于 2011-10-03T19:00:03.430 に答える
3

これは未定義の動作です。変数は、シーケンス ポイント間で複数回変更することはできません。プログラムは何でも出力できます。それ以外の答えは間違っています。

于 2011-10-03T18:57:09.657 に答える
1

C の標準では、優先順位の規則が守られている限り、コンパイラは式を自由に再配置できると明示的に述べています。これは、次の式がある場合を意味します。

x = foo() + bar() + baz()

3 つの関数は任意の順序で呼び出すことができ、それは正当です。

C の古い標準では、必要に応じてコンパイラが括弧を無視できるとさえ述べていました。

x = (foo() + bar()) + baz()

特定の評価順序を強制する唯一の確実な方法は、一時変数を使用することです。

temp0 = foo();
temp1 = bar();
x = temp0 + temp1 + baz();
于 2011-10-03T18:59:45.880 に答える
0

代入している式aは未定義の動作を示します。具体的には、インクリメント/デクリメント操作がオペランドに適用される順序です。

于 2011-10-03T18:57:43.977 に答える
0

コンパイラがすべてを実行する順序に依存します。コンパイラの実装に依存するため、「正しい」答えはありません。

例: 厳密に left->right:

a = (++i) + (i++) + (++i) + (i++) - (--i);
     first   second  third  fourth  fifth
a = (6) + (6) + (8) + (8) - (7) = 21;

右→左:

a = (++i) + (i++) + (++i) + (i++) - (--i);
     fifth   fourth third   second    first
a =  6 + 5 + 5 + 4 - 4 = 16;
于 2011-10-03T19:01:09.343 に答える