鉴于此代码:
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”?
答案 0 :(得分:4)
这只是我个人的看法。我不是100%确信这是正确的。 所以,如果我的回答是错误的,请原谅我。
C99 6.5.2.2/10 函数调用表示:
评估的顺序 功能指示符,实际 参数和子表达式 实际参数未指定, 但之前有一个序列点 实际的电话。
C99 6.5.2.4/2 后缀增量和减量运算符表示:
更新存储的副作用 应该发生操作数的值 在前一个和下一个之间 序列点。
后增量算子的副作用在之前的某个地方完成
下一个序列点。
假设表达式f( x )
,
我认为在评估f
和x
后会有一个序列点,并且
在函数调用之前。
因此,gFP++
的副作用将在函数调用之前完成,
并且问题中的代码应打印Foo Bar
。
修改强>
我在C99和C ++中删除了附件C中的引号,并添加了引号
C99。
可能以前的报价对这个问题不明确。
答案 1 :(得分:1)
取消引用首先发生。这与任何其他后增量相同:使用原始值。
例如,请参阅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仅表示它作为相对于作为参数传入的表达式的序列点 - 它们保证被评估,但没有其他必然(在{{ 1}}访问f(i++) + g(j++)
中的i
或g()
中的j
会调用未定义的行为。)
然而,6.5.5.2(第10页)说:
之后有一个序列点 评估功能指示符 和之前的实际论点 实际的电话。
表示 对f()
进行排序。
答案 2 :(得分:0)
operator precedence table显示C的操作顺序。
在您的示例中,gFP++
具有最高优先级,后跟*gFP
但是,在完成所有其他操作之前,不会进行增量。
所以你最终得到的是取消引用gFP,然后是函数调用,然后gFP的值递增。
所以你最终会出现堆栈溢出。