3

鉴于此代码:

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

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

 Thunk Codex[] = { foo, bar };

 gFP = Codex;

 (*gFP++)();

函数调用发生在增量之前还是之后?
即:这会打印“Foo Foo Foo ...”还是“Foo Bar”?

4

3 回答 3

4

这只是我个人的看法。我不是 100% 相信这是正确的。所以,如果我的回答有误,请见谅。

C99 6.5.2.2/10函数调用说:

函数指示符、实际参数和实际参数中的子表达式的求值顺序未指定,但在实际调用之前有一个顺序点。

C99 6.5.2.4/2后缀递增和递减运算符说:

更新操作数存储值的副作用应发生在前一个序列点和下一个序列点之间。

后自增运算符的副作用在下一个序列点之前的某处完成。假设表达式f( x ),我认为在 and 的评估之后fx函数调用之前有一个序列点。所以,副作用gFP++会在函数调用之前完成,问题中的代码预计会打印出来Foo Bar

编辑: 我从 C99 和 C++ 中的 Annex-C 中删除了引号,并添加了 C99 中的引号。
之前的引述可能对这个问题含糊不清。

于 2011-02-24T20:09:43.870 回答
1

取消引用首先发生。这与任何其他后增量相同:使用原始值。

例如,参见关于序列点的 Post Increment

但是,您的问题似乎是函数指针在内部使用是否foo()会调用foo()bar().

http://newsgroups.derkeiler.com/Archive/Comp/comp.std.c/2009-10/msg00053.html是 comp.std.c 中的一个讨论,标题是“序列点问题”,正是这一点的争论. 我认为它没有达成共识,但双方都有很好的论据。

根据我之前对标准的阅读,这会引发未定义的行为。

对函数的调用充当序列点,但附录 C 仅表示它充当相对于作为参数传入的表达式的序列点——它们保证被评估,但没有其他必然会(在f(i++) + g(j++)访问iing()jinf()调用未定义的行为。)

但是,6.5.5.2(第 10 页)说:

在函数指示符和实际参数的评估之后但在实际调用之前有一个序列点。

这意味着它确实++.

于 2011-02-24T18:11:14.923 回答
0

运算符优先级表显示了 C 的操作顺序。

在您的示例gFP++中,优先级最高,其次是*gFP

但是,直到所有其他操作都完成后才会完成增量。

所以你最终会得到对 gFP 的解引用,然后是函数调用,然后 gFP 的值被递增。

所以你最终会出现堆栈溢出。

于 2011-02-24T18:11:32.630 回答