2

次の例を検討してください。

struct {
    int num;
} s, *ps;

s.num = 0;
ps = &s;
++ps->num;

printf("%d", s.num); /* Prints 1 */

印刷し1ます。
したがって、演算子の優先順位によると、->が よりも高い++ため、最初に値ps->num(0) がフェッチされ、次に++演算子がそれを操作するため、1 にインクリメントされるためだと理解しています。

struct {
    int num;
} s, *ps;

s.num = 0;
ps = &s;
ps++->num;

printf("%d", s.num); /* Prints 0 */

この例では0、理由がわかりません。最初の例の説明は、この例でも同じです。しかし、この式は次のように評価されるようです:最初
に、演算子++が動作し、 に動作するpsため、次の にインクリメントしますstruct。それからのみ動作し、次のフィールドを->フェッチするだけで何もしないため、何もしません。 しかし、これは演算子の優先順位と矛盾しています。numstruct
->++

誰かがこの動作を説明できますか?

編集:プレフィックス/演算子の優先順位が よりも低い
ことを示す C++ 優先順位テーブルを参照する 2 つの回答を読んだ後、グーグル検索を行い、このルールが C 自体にも適用されることを示すこのリンクを思いつきました。それは正確に適合し、この動作を完全に説明していますが、このリンクの表は、K&R ANSI C の私自身のコピーの表と矛盾していることを付け加えなければなりません。++--->

ありがとう。

4

8 に答える 8

4

C では、ポスト インクリメント ( ps++) とプリ インクリメント ( ++ps) の結合性が異なります。前者は左から右に関連付けられますが、後者は右から左に関連付けられます。このページを確認してください (ただし、これは C++ 用であるため、優先順位が誤解を招く可能性があります)。

最後の例では、ポインターを の末尾を過ぎた 1 つに変更しています&s。ポインティの値を変更していません。をインクリメントする必要がある場合はnum、 を にバインドする必要があり++ますnum

詳細な説明:

 ps++->num;

(仮想の) コンパイラは、この式を見て、psオブジェクトをスタックにプッシュし、続いて++演算子、->演算子、最後にオブジェクト --をプッシュする場合がありますnum。評価中、コンパイラはどこから始めるべきですか? 利用可能な演算子、つまり++と を調べます->。選ぶps++ps?ここでの優先規則:->は よりも優先順位が高いため、一方のオペランドとして処理し、もう一方のオペランドとして処理する++必要があります。したがって、当然のことながら、式の値は 0 になります。評価後はどうなるの?スタックに別のオペレーターが残っていることを覚えていますか? したがって、コンパイラはこれを->numpsps->numpspsそして、現在は 1 つ過ぎた要素を指してい&sます。

脚注:

ANSI/ISO C 標準では、演算子優先文法は使用されません。むしろ、完全に因数分解された文法として知られているものを使用します。これには通常、「primary-expression」や「shift-expression」などの多数の非終端記号が点在する厳密な文法定義が含まれます。これは理解しにくいですが、言語設計者やコンパイラ ベンダーにとっては理解しやすいものです。また、そのような文法は優先順位を簡単にエンコードできます。ただし、完全に因数分解された文法は、演算子優先文法と互換性があり、これはほとんどの本 (および Web サイト) が行うことです (また、時々混乱します)。

于 2009-04-22T10:29:28.330 に答える
4

++ の優先度が高くても、これは値を変更しません -> ポストインクリメントであるため、動作します。この動作の別の例もあるこのコードを参照してください。

int b = 5;
int a = b++ * 3;
b = 5;
int c = (b++) * 3;

printf("%i, %i, %i\n", a, b, c); // Prints 15, 6, 15

struct {
  int num;
} s, *ps;

s.num = 35;
ps = &s;
printf("%p\n", ps); // Prints the pointer
printf("%i\n", ps++->num); // Prints 35
printf("%p\n", ps); // Prints the increased pointer

printf("%d\n", s.num); /* Prints 35 */
于 2009-04-22T10:30:41.883 に答える
3

b = ++a; 次と同等です。

a += 1;
b = a;

b = a++; 次と同等です。

b = a;
a += 1;

したがって、探している結果が得られない理由は明らかです。あなたが説明したことは、(++ps)->num と同等です。

于 2009-04-22T10:39:51.487 に答える
1

「優先度」は基本的に派生プロパティです。構文解析規則に従います。++ps->num は ++(ps->num) として解析されます /* 解析規則を明確にするために () が追加されました */ 一方、ps++->num は (ps++)->num としてのみ解析できます。

于 2009-04-22T10:31:45.097 に答える
1

これは、優先順位が異なり、同じグループ内で特定の結合性 (評価順序など) があるためだと思います。

ここで確認してください。後置演算子の優先度はポインター解決と同じですが、前置演算子の優先度は低くなります。

于 2009-04-22T10:31:52.630 に答える
1

ps++->num は、ポインター ps を 1 インクリメントし、その中のデータを読み取ります。ps はスタック上の s の直後にあるため、ポインターは自分自身を指している可能性が高いと思いますが、これは確信が持てず、重要ではありません。基本的に、最初のプログラムは ++(ps->num) を実行していましたが、括弧はありません。同じことを達成するには、データにアクセスした後、(ps->num)++ を実行するか、括弧なしで実行する必要があります: ps->num++.

ps は単なるポインタなので、値を変更しても s は変わりません。

于 2009-04-22T10:35:57.177 に答える
0

ここで、接頭辞としての ++ は -> よりも優先度が低いことがわかりますが、接尾辞としては -> と同じ優先度であり、左から右に評価されるため、ps++ が最初に実行され、次に -> が実行されます。

編集:これはCではなくC ++用です。したがって、私の答えは正しくありません。

于 2009-04-22T10:29:23.557 に答える
0

優先順位は、あいまいな解析を解決するために使用されます。または++ps->numとして解析できます。と の相対的な優先順位により、後者が正しい解析であると判断されます。((++ps)->num)(++(ps->num))++()->

の場合ps++->num、有効な解析は 1 つだけな((ps++)->num)ので、演算子の優先順位は関係ありません。

于 2010-03-01T20:06:28.873 に答える