Что означает ( * ) in plain C?

Я не могу получить значение выражения "( * ) " в следующем утверждении:

#define PySpam_System 
 (*(PySpam_System_RETURN (*)PySpam_System_PROTO) PySpam_API[PySpam_System_NUM])

здесь

#define PySpam_System_NUM 0
#define PySpam_System_RETURN int
#define PySpam_System_PROTO (const char *command)

(выдержка из http://docs.python.org/2/extending/extending.html). Что бы это значило? (Извините за глупый вопрос). Напоминает указатель функции, но с очень запутанным синтаксисом.

UPDATE: благодаря Шахбазу и Джонатану все становится в основном ясно, но я все еще не могу получить два нюансы:

  1. почему const char *command не только const char *. Я думал, что имя аргумента должно быть опущено в объявлении типа указателя функции и преобразовании типа? Значит, его нельзя опускать, а скорее просто можно?
  2. почему (*(int (*)(const char *command)) не только (int (*)(const char *command)? Какова цель внешнего (*[всем остальным])? Это необязательное разыменование указателя функции на саму функцию, верно?

2 ответов


PySpam_System_RETURN (*)PySpam_System_PROTO

расширяется:

int (*)(const char *command)

это тип указателя функции. Итак, в основном следующее:

(*(PySpam_System_RETURN (*)PySpam_System_PROTO) PySpam_API[PySpam_System_NUM])

что переводится как:

(*(int (*)(const char *command)) PySpam_API[0])

звонит, стоимостью PySpam_API[0] как будто это функция с и int возвращаемое значение (приведение к указатель на функцию). Обратите внимание, что это все еще не хватает аргументов, поэтому тот, кто использует макрос, должен дать ему аргументы, такие как:

PySpam_System("some string");

на ваш update:

  1. имя аргумента является необязательным. Они могли просто написать const char *. Кажется, это имя было написано для ясности. Прямо сейчас, не глядя куда-либо еще, я понял, что функция принимает команду, поэтому я бы сказал, что это полезно.
  2. опять вы правы. Инициал * разыменование указателя функции. В C это совершенно необязательно. Было бы более симметрично поставить его, так как вы разыменовываете указатель, но так как нет разыменование указателя функции не имеет смысла, если вы не разыменуете его, это не будет иметь никакого значения, C сделает для вас единственную нормальную вещь. На самом деле, даже если вы положите ****** вместо одного, он все равно будет работать.

расширения PySpam_System с препроцессором, и вы увидите:

(*(int (*)(const char *command)) PySpam_API[0])

выражение (более или менее) приведено к указателю на функцию, возвращающую int и принимающую один аргумент типа const char *'. За ним должны были последовать:--9--> для преобразования целого В вызов функции с помощью указателя на функцию. Таким образом, в коде, вы можете увидеть:

PySpam_System("abc");

и компилятор увидит:

(*(int (*)(const char *command)) PySpam_API[0])("abc");

и это вызов функции, хранящиеся в массив PySpam_API в местоположении индекса 0. Очевидно, что аргумент, вероятно, не будет простым строковым литералом, но простой строковый литерал является представителем const char *.


обновления вопрос

почему const char *command не только const char *. Я думал, что имя аргумента должно быть опущено в объявлении типа указателя функции и преобразовании типа? Значит, его нельзя опускать, а скорее просто можно?

имена для аргументы (например,command в Примере) являются необязательными в декларации прототипа. Также нет правила, указывающего, что имя в объявлении прототипа должно совпадать с именем в определении функции. К сожалению, C еще не принял соглашение c++ о том, что имена являются необязательными в определении функции, если вы пишете функцию в соответствии с интерфейсом, но конкретная реализация функции не нуждается в аргументе. То есть в C++ вы можете пиши:

typedef int (*interface)(const char *cmd, int arg1, int arg2);

static int implementation(const char *cmd, int arg1, int)  // C++, not C
{
    return some_other_function(cmd, arg1, 23, 19);
}

функции implementation соответствует interface введите, но не использует arg2 аргумент, но компилятор не будет жаловаться на неиспользуемый аргумент. C не допускает такого удобства, поэтому вам говорят о "неиспользуемом аргументе", хотя вы прекрасно знаете, что он не используется. Я считаю, что есть способы компилятора вокруг этой конкретной проблемы.

почему (*(int (*)(const char *command)) не только (int (*)(const char *command)? Какова цель внешней (*[everything else here])? Это необязательное разыменование указателя функции на саму функцию, верно?

право.

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

требуется старая нотация (плюс-минус прототипы, которые не были доступны в то время):

#include <math.h>

double (*func)(double) = sin;

double x = (*func)(1.0);

С скобки и * вокруг указателя на функцию. Идея заключается в том, что если у вас есть указатель на функцию, вам нужно разыменовать ее для вызова функции. Более современная нотация отмечает, что имя функции становится указателем на функцию (например, в назначении), поэтому вам действительно не нужно (*func) нотации. Следовательно, новый стиль:

#include <math.h>

double (*func)(double) = sin;

double x = func(1.0);

так как я узнал C, когда старый стиль был обязательным, я все еще предпочитаю немного более подробный, но совершенно однозначное обозначение. Код PySpam_System макрос также использует более старые обозначения.

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

double (*funca)(double) =   &sin;
double (*func0)(double) =    sin;
double (*func1)(double) =   *sin;
double (*func2)(double) =  **sin;
double (*func3)(double) = ***sin;

только func0 декларация разумна; остальные-запутывающие C.