Прямое объявление функции typedef в C

#c

Вопрос:

У меня есть ноющее подозрение, что об этом уже спрашивали раньше, но я его не нахожу…

Предположим, у меня есть typedef для функции A, которая принимает указатель на функцию с typedef B, которая, в свою очередь, принимает функцию typedef A. Если бы одна из них была структурой, я знаю, как бы я обрабатывал прямое объявление, но для функций я не знаю синтаксиса. Есть ли такой?

Я хочу быть в состоянии сделать:

 typedef void (*function_A_t)(function_B_t f_B);
typedef void (*function_B_t)(function_A_t f_A);
 

Есть какие-нибудь намеки? Еще лучше, ссылка? Кстати, это на самом деле только что произошло со мной, но я смог исправить это по-другому, хотя на самом деле это было бы более плавным (лучше развязаться, меньше шансов, что следующий парень все испортит), если это возможно.

Ответ №1:

Вы можете сделать это, воспользовавшись тем фактом, что C указывает, что объявление функции без аргументов означает, что оно принимает неопределенное количество аргументов.

Таким образом, вы могли бы сделать это следующим образом:

 typedef void (*function_A_t)(void (*)());
typedef void (*function_B_t)(function_A_t f_A);
 

Что позволяет скомпилировать следующее:

 void A(function_B_t b)
{
    b(A);
}

void B(function_A_t a)
{
    a(B);
}

int main()
{
    function_A_t a = A;
    function_B_t b = B;
    a(B);
    b(A);
    return 0;
}
 

В разделе 6.7.6.3p15 стандарта C говорится следующее относительно совместимости типов функций:

Для совместимости двух типов функций оба должны указывать совместимые типы возвращаемых данных. Кроме того, списки типов параметров, если присутствуют оба, должны совпадать по количеству параметров и использованию многоточия; соответствующие параметры должны иметь совместимые типы. Если у одного типа есть список типов параметров, а другой тип указан декларатором функций, который не является частью определения функции и содержит пустой список идентификаторов, список параметров не должен иметь многоточия, и тип каждого параметра должен быть совместим с типом, который является результатом применения повышений аргументов по умолчанию. Если у одного типа есть список типов параметров, а другой тип задан определением функции, содержащим (возможно, пустой) список идентификаторов, оба должны согласовываться по количеству параметров, и тип каждого параметра прототипа должен быть совместим с типом, который является результатом применения повышений аргумента по умолчанию к типу соответствующего идентификатора. (При определении совместимости типов и составного типа каждый параметр, объявленный с типом функции или массива, принимается как имеющий скорректированный тип, а каждый параметр, объявленный с определенным типом, принимается как имеющий неквалифицированную версию своего объявленного типа.)

Часть, выделенная жирным шрифтом выше, указывает, что void (*)() совместима с void (*)(function_B_t)

Комментарии:

1. К каким версиям C это относится?

2. Кроме того, правильно ли я понимаю, что это будет работать, но уменьшит способность компилятора проверять списки параметров в момент вызова?

3. @Basya Приведенная выше стандартная цитата взята из C11, но она применима к C89 и более поздним версиям. И да, это позволит использовать любой указатель на функцию, который имеет void тип возвращаемого значения в качестве параметра. Это не идеально, но лучшее, что мы можем сделать.

4. Спасибо! Я программирую на Си уже много лет, и это было для меня в новинку…

5. @dbush Это здорово! Отдельное спасибо за ссылку на стандарт.