Как понять это определение

В настоящее время я читал APUE. И нашел функцию, определенную ниже:

void (*signal(int signo, void (*func)(int)))(int);

я был сбит с толку, я знаю, что сигнал является указателем на функцию, а последний (int) является его параметром. я не знал, что это (int signo,void (*func)(int)).

6 ответов

Решение

Общая процедура: найдите самый левый идентификатор и проложите себе путь. Отсутствие явной группировки с круглыми скобками, такими постфиксными операторами, как () а также [] связать, прежде чем унарные операторы, такие как *; Таким образом, все это верно:

T *x[N]             -- x is an N-element array of pointer to T
T (*x)[N]           -- x is a pointer to an N-element array of T
T *f()              -- f is a function returning a pointer to T
T (*f)()            -- f is a pointer to a function returning T

Применяя эти правила к декларации, она разбивается на

       signal                                      -- signal
       signal(                            )        -- is a function
       signal(    signo,                  )        -- with a parameter named signo 
       signal(int signo,                  )        --   of type int
       signal(int signo,        func      )        -- and a parameter named func
       signal(int signo,       *func      )        --   of type pointer
       signal(int signo,      (*func)(   ))        --   to a function
       signal(int signo,      (*func)(int))        --   taking an int parameter
       signal(int signo, void (*func)(int))        --   and returning void
      *signal(int signo, void (*func)(int))        -- returning a pointer
     (*signal(int signo, void (*func)(int)))(   )  -- to a function
     (*signal(int signo, void (*func)(int)))(int)  -- taking an int parameter
void (*signal(int signo, void (*func)(int)))(int); -- and returning void

Короче, signal возвращает указатель на функцию, возвращающую void, signal принимает два параметра: целое число и указатель на другую функцию, возвращающую void,

Вы можете использовать typedefs, чтобы сделать это проще для чтения (и справочную страницу для signal в Ubuntu Linux именно это и делает); Тем не менее, я думаю, что полезно показать версию без определения типа, чтобы продемонстрировать, как именно работает синтаксис. Функция typedef замечательна, но вам действительно нужно понять, как работают базовые типы, чтобы эффективно ее использовать.

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

Например, если вы хотите, чтобы ваша программа обрабатывала сигналы прерывания (например, от Ctrl-C):

static int g_interruptFlag = 0;

void interruptHandler(int sig)
{
  g_interruptFlag = 1;
}

int main(void)
{
  ...
  /**
   * Install the interrupt handler, saving the previous interrupt handler
   */
  void (*oldInterruptHandler)(int) = signal(SIGINT, interruptHandler);

  while (!g_interruptFlag)
  {
    // do something interesting until someone hits Ctrl-C
  }

  /**
   * Restore the previous interrupt handler (not necessary for this particular
   * example, but there may be cases where you want to swap out signal handlers
   * after handling a specific condition)
   */
  signal(SIGINT, oldInterruptHandler);
  return 0;
}

РЕДАКТИРОВАТЬ Я расширил пример кода для signal к чему-то, что, надеюсь, более иллюстративно.

void (*signal(int signo, void (*func)(int)))(int);

signal - это функция, которая принимает int, а указатель на функцию принимает int и возвращает void и возвращает указатель на функцию, принимающий int и возвращающий void. То есть,

typedef void(*funcPtr)(int)

тогда мы имеем

funcPtr signal(int signo, funcPtr func); //equivalent to the above

Синтаксис действительно странный, и такие вещи лучше делать с помощью typedef. Например, если вы хотите объявить функцию, которая принимает int и возвращает указатель на функцию, принимающую char и возвращающую double, будет

double (*f(int))(char);

Изменить: после комментария, который гласит "Wooooooow", я приведу еще один пример, который является более "woooow":)

Давайте объявим функцию, которая принимает
1. указатель на массив из 5 указателей на функции, каждая из которых принимает float и возвращает double.
2. указатель на массив из 3 понтеров для массивов из 4-х целых
и возвращает указатель на функцию, которая принимает указатель на функцию, принимая int и возвращая указатель на функцию, принимающую float и возвращающую void, и возвращает unsigned int.

Решение typedef будет следующим:

typedef double (*f1ptr) (float);
typedef f1ptr (*arr1ptr)[5];
typedef int (*arr2ptr)[4];
typedef arr2ptr (*arr3ptr)[3];
typedef void(*f2Ptr)(float);
typedef f2ptr (*f3ptr)(int);
typedef unsigned int (*f4ptr) (f3ptr);
f4ptr TheFunction(arr1ptr arg1, arr3ptr arg2);

Теперь забавная часть:) Без typedefs это будет:

 unsigned int (*TheFunction( double (*(*)[5])(float), int(*(*)[3])[4]))( void(*(*)(int))(float))

Боже мой, я только что написал это?:)

Правило "Спираль по часовой стрелке" поможет: http://c-faq.com/decl/spiral.anderson.html

Есть три простых шага:

Начиная с неизвестного элемента, двигайтесь по спирали / по часовой стрелке; при обнаружении следующие элементы заменяют их соответствующими английскими выражениями:

[X] или [] => Размер массива X... или неопределенный размер массива...

(type1, type2) => функция, передающая type1 и type2, возвращающая...

  • => указатель (и) на...

Продолжайте делать это по спирали / по часовой стрелке, пока все жетоны не будут закрыты. Всегда сначала разрешите что-нибудь в скобках!

Смотрите "Пример № 3:" Окончательный "", который в точности соответствует тому, что вы просите:

"сигнал - это функция, передающая int и указатель на функцию, передающую int, ничего не возвращающая (void), возвращающая указатель на функцию, передающую int, ничего не возвращающую (void)"

Если у вас нет доступа к cdecl прямо сейчас, вот вывод cdecl:

$ cdecl
cdecl> explain void (*signal(int , void (*)(int)))(int);
declare signal as function (int, pointer to function (int) returning void) returning pointer to function (int) returning void

Этот сайт дает комментарии к C тарабарщины:

C gibberish <-> английский

Установите cdecl для вашего дистрибутива (если есть) или перейдите сюда

В противном случае, я считаю, что ответ Армена Цируняна верен.

Другие вопросы по тегам