3

このコードを考えると:

 typedef void (*Thunk)();
 Thunk* gFP;

 void foo(){ printf("Foo "); *gFP(); };
 void bar(){ printf("Bar ");

 Thunk Codex[] = { foo, bar };

 gFP = Codex;

 (*gFP++)();

関数呼び出しは増分の前または後に発生しますか?
すなわち:これは「FooFoo Foo ...」または「FooBar」を印刷しますか?

4

3 に答える 3

4

これは私の個人的な見解です。私はこれが正しいと100%確信しているわけではありません。ですから、私の答えが間違っていたら許してください。

C99 6.5.2.2/10関数呼び出しは次のように述べています。

関数指定子、実際の引数、および実際の引数内の部分式の評価の順序は指定されていませんが、実際の呼び出しの前にシーケンスポイントがあります。

C99 6.5.2.4 /2Postfixインクリメントおよびデクリメント演算子は次のように述べています。

オペランドの格納値を更新する副作用は、前のシーケンスポイントと次のシーケンスポイントの間で発生します。

ポストインクリメント演算子の副作用は、次のシーケンスポイントの前のどこかで完了します。式を仮定すると、との評価後、関数呼び出しの前にf( x )シーケンスポイントがあると思います。したがって、の副作用は関数呼び出しの前に完了し、問題のコードは出力されると予想されます。fxgFP++Foo Bar

編集: C99およびC ++のAnnex-Cから引用符を削除し、C99から引用符を追加しました。
おそらく以前の引用は質問に関して不明瞭でした。

于 2011-02-24T20:09:43.870 に答える
1

逆参照が最初に発生します。これは、他のポストインクリメントと同じです。元の値が使用されます。

たとえば、シーケンスポイントに関するポストインクリメントを参照してください。

ただし、あなたの質問は、関数ポインタが内部で使用するのか、それともfoo()を呼び出すのfoo()かということのようbar()です。

http://newsgroups.derkeiler.com/Archive/Comp/comp.std.c/2009-10/msg00053.htmlは、comp.std.cでの議論であり、この点について正確に議論するヘッダー「シーケンスポイントの問題」があります。 。コンセンサスが得られたとは思いませんが、双方に良い議論がありました。

私が以前に標準を読んだことによると、これは未定義の動作を引き起こします。

関数の呼び出しはシーケンスポイントとして機能しますが、付録Cは、パラメーターとして渡された式に関連するシーケンスポイントとして機能することのみを示しています。これらは評価されることが保証されていますが、他の方法では必ずしも評価されません(inまたはinのf(i++) + g(j++)いずれかにアクセスする場合)。未定義の動作を呼び出します。)ig()jf()

ただし、6.5.5.2(p 10)は次のように述べています。

関数指定子と実際の引数の評価の後、実際の呼び出しの前にシーケンスポイントがあります。

これは、シーケンスを実行することを意味ます++

于 2011-02-24T18:11:14.923 に答える
0

演算子の優先順位の表は、Cの操作の順序を示しています。

あなたの例でgFP++は、が最も優先順位が高く、次に*gFP

ただし、他のすべての操作が完了するまで、増分は実行されません。

したがって、最終的には、gFPで間接参照が動作し、次に関数呼び出しが行われ、次にgFPの値がインクリメントされます。

そのため、スタックオーバーフローが発生します。

于 2011-02-24T18:11:32.630 に答える