Синтаксис вызова указателей на функции C - PullRequest
3 голосов
/ 24 декабря 2011

Предположим, есть указатель на функцию:

void func(float a1, float a2) {

}

void (*fptr)(float, float) = &func;

Есть ли какая-либо разница между этими двумя строками (и компилировать, и работать на моем компиляторе)?

(*fptr)(1,2);
fptr(1,2);

Я полагаю, что вторая версия является просто ярлыком первой, но хочу убедиться в этом. И важнее ли это стандартное поведение?

Ответы [ 2 ]

6 голосов
/ 24 декабря 2011

Они делают то же самое.

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

Выражение типа указателя, например имяобъявленная функция.неявно преобразуется в указатель на эту функцию, если только это не операнд унарного "&" (который в любом случае возвращает адрес функции) или sizeof (что является недопустимым, а не дает размер указателя).

Следствием этого правила является то, что все они:

&func
func
*func
**func

эквивалентны.Все они вычисляются по адресу функции и могут все (если они заключены в соответствующие скобки) использоваться в качестве префикса вызова функции.

6 голосов
/ 24 декабря 2011

Да, это стандартное поведение и будет работать во всех компиляторах C.

Вызовы функций всегда выполняются через указатель на функцию:

6.5.22 "Вызовы функций":

Выражение, которое обозначает вызываемую функцию (сноска 77), должно иметь указатель типа на функцию, возвращающую void или возвращающую тип объекта, отличный от типа массива

Как указывает сноска 77, «нормальный» идентификатор функции фактически преобразуется в указатель на функцию, когда используется вызов функции в выражении:

Сноска 77:

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

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

6.5.3.2 / 4 «Операторы адреса и косвенности»:

The unary * operator denotes indirection. If the operand points to a function, the result is a function designator

Итак, что касается стандарта, для ваших примеров:

(*fptr)(1,2);
fptr(1,2);

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

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

func(1,2);
(*func)(1,2);  // equivalent to the above

Не то, чтобы на самом деле был какой-то оправданный смысл делать это, о чем я могу думать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...