给定以下代码:
typedef void (*Thunk)();
Thunk* gFP;
void foo(){ printf("Foo "); *gFP(); };
void bar(){ printf("Bar ");
Thunk Codex[] = { foo, bar };
gFP = Codex;
(*gFP++)();函数调用发生在增量之前还是之后?
即:这会打印“foo...”吗?还是"Foo Bar"?
发布于 2011-02-25 04:09:44
这只是我个人的观点。我不是100%确信这是正确的。所以,如果我的答案是错的,请原谅我。
C99 6.5.2.2/10函数调用表示:
未指定函数指示符、实际参数和子表达式在实际参数中的求值顺序,但在实际调用之前有一个序列点。
C99 6.5.2.4/2后缀递增和递减运算符表示:
更新操作数存储值的副作用应发生在前一个序列点和下一个序列点之间。
后增量运算符的副作用在下一个序列点之前完成。假设表达式为f( x ),我认为在f和x求值之后和函数调用之前有一个序列点。因此,gFP++的副作用将在函数调用之前完成,并且问题中的代码将打印Foo Bar。
编辑:我在C99和C++中删除了附录C中的引号,并添加了C99中的引号。
可能之前的引文对于这个问题是模糊的。
发布于 2011-02-25 02:11:15
首先会发生取消引用。这与任何其他后增量是相同的:使用原始值。
例如,请参见Post Increment with respect to Sequence Points
但是,您的问题似乎是foo()内部使用的函数指针将调用foo()还是bar()。
http://newsgroups.derkeiler.com/Archive/Comp/comp.std.c/2009-10/msg00053.html是在comp.std.c中的一个讨论,标题为“序列点问题”,正是在这一点上进行了争论。我不认为双方达成了共识,但双方都有很好的理由。
根据我之前对该标准的阅读,这将调用未定义的行为。
对函数的调用充当序列点,但附录C仅说明它充当相对于作为参数传入的表达式的序列点--它们肯定会被求值,但其他函数不一定会求值(在f(i++) + g(j++)中,访问g()中的i或在f()中访问j都会调用未定义的行为)。
然而,6.5.5.2 (第10页)说:
在函数指示符和实际参数的求值之后,但在实际调用之前有一个序列点。
这意味着它确实对++进行了排序。
发布于 2011-02-25 02:11:33
operator precedence table显示了C语言的操作顺序。
在您的示例中,gFP++的优先级最高,其次是*gFP
但是,直到所有其他操作都完成后,才会进行递增。
因此,您最终将在gFP上执行取消引用操作,然后是函数调用,然后是gFP的值递增。
所以你最终会得到一个堆栈溢出。
https://stackoverflow.com/questions/5108664
复制相似问题