Подтвердить что ты не робот

Как это понять

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

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

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

4b9b3361

Ответ 1

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

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, чтобы сделать это проще для чтения (и man-страница для signal в Ubuntu linux делает именно это); однако, я думаю, что это важно, чтобы показать версию non-typedef'd, чтобы продемонстрировать, как работает синтаксис. Средство 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;
}

EDIT. Я расширил примерный код для signal на то, что, надеюсь, более наглядное.

Ответ 2

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-х ponters для массивов из 4-х ints
и возвращает указатель на функцию, которая принимает указатель на функцию, принимающую 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))

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

Ответ 3

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

Существует три простых шага:

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

[X] или [] = > Размер массива X... или Array undefined размер...

(type1, type2) = > передача функции type1 и type2 return...

  • = > указатель для...

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

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

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

Ответ 4

Если у вас нет доступа к 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

Ответ 6

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

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