(*)在普通C中意味着什么?

Bor*_*kov 6 c pointers

我无法在以下语句中获得"(*)"表达式的含义:

#define PySpam_System \
 (*(PySpam_System_RETURN (*)PySpam_System_PROTO) PySpam_API[PySpam_System_NUM])
Run Code Online (Sandbox Code Playgroud)

哪里

#define PySpam_System_NUM 0
#define PySpam_System_RETURN int
#define PySpam_System_PROTO (const char *command)
Run Code Online (Sandbox Code Playgroud)

(摘自http://docs.python.org/2/extending/extending.html).这意味着什么?(请原谅我一个愚蠢的问题).类似于函数指针,但语法非常混乱.

更新:感谢Shahbaz和Jonathan,事情变得越来越明显,但我仍然无法获得两个细微差别:

  1. 为什么const char *command,不只是const char *.我认为在函数指针类型声明和类型转换中应该省略参数的名称?所以一定不能省略,而是可以吗?
  2. 为什么(*(int (*)(const char *command)),不仅仅是(int (*)(const char *command)?外部(*[其他一切在这里] 的目的是什么)?它是对函数本身的函数指针的可选解引用,对吧?

Sha*_*baz 7

PySpam_System_RETURN (*)PySpam_System_PROTO
Run Code Online (Sandbox Code Playgroud)

扩展为:

int (*)(const char *command)
Run Code Online (Sandbox Code Playgroud)

这是一个函数指针类型.所以基本上如下:

(*(PySpam_System_RETURN (*)PySpam_System_PROTO) PySpam_API[PySpam_System_NUM])
Run Code Online (Sandbox Code Playgroud)

转换为:

(*(int (*)(const char *command)) PySpam_API[0])
Run Code Online (Sandbox Code Playgroud)

正在调用它的值,PySpam_API[0]就好像它是一个带有const char*参数和int返回值的函数(强制转换为函数指针).请注意,这仍然缺少参数,因此无论谁使用宏都应该为它提供参数,例如:

PySpam_System("some string");
Run Code Online (Sandbox Code Playgroud)

在您的更新:

  1. 参数名称是可选的.他们本来可以写的const char *.我相信这个名字是为了清晰起见而写的.现在,在没有其他任何地方的情况下,我明白该功能需要一个命令,所以我会说这很有帮助.
  2. 再一次,你是对的.初始*取消引用函数指针.在C中,这是非常可选的.把它放得更加对称,因为你正在取消引用一个指针,但是由于没有取消引用一个函数指针没有意义,如果你不取消引用它就没有任何区别,C会做唯一合理的事情为了你.事实上,即使你******只使用一个,它仍然可以工作.


Jon*_*ler 5

PySpam_System使用预处理器进行扩展,您会看到:

(*(int (*)(const char *command)) PySpam_API[0])
Run Code Online (Sandbox Code Playgroud)

表达式(或多或少)是一个强制转换为'指向函数的指针返回int并取一个类型const char *的参数'.接下来("something")必须通过指向函数的指针将整个转换为函数调用.因此,在代码中,您可能会看到:

PySpam_System("abc");
Run Code Online (Sandbox Code Playgroud)

并且编译器会看到:

(*(int (*)(const char *command)) PySpam_API[0])("abc");
Run Code Online (Sandbox Code Playgroud)

这是对存储在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);
}
Run Code Online (Sandbox Code Playgroud)

该函数implementation符合interface类型,但不使用arg2参数,但编译器不会抱怨未使用的参数.C不允许这样的方便,所以即使你完全清楚它未被使用,你也会被告知'未使用的参数'.我相信这个特定问题有特定于编译器的方法.

为什么(*(int (*)(const char *command)),不仅仅是(int (*)(const char *command)?外在的目的是(*[everything else here])什么?它是对函数本身的函数指针的可选解引用,对吧?

对.

请注意,有两种方法可以通过指向函数的指针来调用函数,大致是"旧"和"新"(其中new表示"由C89标准引入和祝福",因此它并不完全是'新').

需要旧的表示法(给出或采取当时不可用的原型):

#include <math.h>

double (*func)(double) = sin;

double x = (*func)(1.0);
Run Code Online (Sandbox Code Playgroud)

括号和*函数指针周围.这个想法是,如果你有一个指向函数的指针,你需要取消引用它来调用该函数.更现代的符号表明函数的名称成为函数的指针(例如在赋值中),因此您不需要(*func)表示法.因此,较新的风格是:

#include <math.h>

double (*func)(double) = sin;

double x = func(1.0);
Run Code Online (Sandbox Code Playgroud)

由于我在旧风格必修时学会了C语言,我仍然更喜欢略显冗长但完全明确的符号.PySpam_System宏中的代码也使用旧的表示法.

您还可以使用函数指针玩各种愚蠢的游戏,添加额外的*和使用a &,所有这些都是不必要的.

double (*funca)(double) =   &sin;
double (*func0)(double) =    sin;
double (*func1)(double) =   *sin;
double (*func2)(double) =  **sin;
double (*func3)(double) = ***sin;
Run Code Online (Sandbox Code Playgroud)

只有func0宣言是明智的; 其余的是混淆C.