Что происходит в первую очередь при разыменовании и постинкрементном указателе на указатель на функцию? - PullRequest
3 голосов
/ 24 февраля 2011

С учетом этого кода:

 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»?

Ответы [ 3 ]

4 голосов
/ 24 февраля 2011

Это только мой личный взгляд. Я не уверен на 100%, что это правильно. Поэтому, пожалуйста, прости меня, если мой ответ неверен.

C99 6.5.2.2/10 Функциональные вызовы говорит:

Порядок оценки обозначение функции, фактическое аргументы и подвыражения внутри фактические аргументы не определены, но есть точка последовательности перед фактический звонок.

C99 6.5.2.4/2 Постфиксные операторы увеличения и уменьшения говорит:

Побочный эффект обновления хранимых значение операнда должно произойти между предыдущим и следующим точка последовательности.

Побочный эффект постинкрементного оператора завершается где-то перед следующая точка последовательности. Предполагая выражение f( x ), Я думаю, что есть точка последовательности после оценки f и x, и до вызова функции. Таким образом, побочный эффект gFP++ будет завершен до вызова функции, и код в вопросе, как ожидается, напечатает Foo Bar.

Edit: Я удалил цитаты из Приложения-C в C99 и C ++ и добавил цитаты из C99.
Возможно, предыдущие цитаты были нечеткими по этому вопросу.

1 голос
/ 24 февраля 2011

Разыменование происходит первым. Это то же самое, что и любой другой постинкремент: используется оригинальное значение.

См., Например, Постинкремент относительно пунктов последовательности

Однако ваш вопрос, похоже, заключается в том, вызовет ли использование указателя функции внутри foo() вызов 100 * или bar().

http://newsgroups.derkeiler.com/Archive/Comp/comp.std.c/2009-10/msg00053.html - это обсуждение в comp.std.c с заголовком «проблема точки последовательности», в котором обсуждается именно эта точка. Я не думаю, что это достигло консенсуса, но с обеих сторон были веские аргументы.

По моему предыдущему прочтению стандарта, это вызвало бы неопределенное поведение.

Вызов функции действует как точка последовательности, но в приложении C говорится только, что она действует как точка последовательности относительно выражений, переданных в качестве параметров - они гарантированно будут оценены, но больше ничего не обязательно (в f(i++) + g(j++) доступ к i в g() или j в f() вызывает неопределенное поведение.)

Однако, 6.5.5.2 (p 10) говорит:

Существует точка последовательности после оценки обозначения функции и фактические аргументы, но до фактический звонок.

, что означает, что выполняет последовательность ++.

0 голосов
/ 24 февраля 2011

Таблица приоритетов операторов показывает порядок операций для C.

В вашем примере gFP++ имеет самый высокий приоритет, за которым следует *gFP

Однако приращение не будет выполнено до тех пор, пока все другие операции не будут завершены.

В результате вы получите разыменование, работающее с gFP, затем вызов функции, а затем значение gFP, которое увеличивается.

Таким образом, вы получите переполнение стека.

...