typedef A (*AF)() 的意思是什么?

14

我的主要编程语言最近开源了。为了改进它,我正在研究用C语言编写的源代码。

但是我已经很久没有读过或写过C语言了,即使当时也不是很擅长。而且这个特定代码库的编写方式是...特别的(许多APL解释器,包括J在内,其源代码是用高级“APL风格”编写的,即使是用低级语言编写的;非常简洁,避免冗余,大量使用宏等)

目前,我正在尝试理解它所使用的基本数据结构。其中最基本的一个是typedef A("A"代表 "数组"):

typedef struct {I k,flag,m,t,c,n,r,s[1];}* A;

我对前面的内容有所了解。但是在两行之后,我很难理解 AF 是什么。

typedef A (*AF)();

这个语法是什么意思?特别是当事物后来被声明为“类型AF”时,它是什么意思?一个AF只是指向A的指针吗?

我的直接目标是解释包括type V的东西的内存转储(用于“verb”),其前两个成员是AF

typedef struct {AF f1,f2;A f,g,h;I flag,mr,lr,rr,fdep;C id;} V;

但我的总体目标不仅限于此,请详细阐述在定义AF时所使用的语法。

5
AF是一个指向不带参数且返回类型为A的函数的指针。 - Sergey Kalinichenko
8
在C++中是真的。在C中,它是一个具有未指定但固定数量和类型参数并返回 A 的函数的typedef 。非常可能应该定义为 typedef A (*AF)(void);。如果它确实意味着要接受任意数量的参数,则通过错误调用函数很容易导致未定义行为,并且编译器也不会给出任何诊断信息。 - Keith Thompson
8
这个代码库糟糕透了。你应该立即逃离。 - Hogan
4
在C语言中,无法指定一个函数可以接收一个或两个参数。大多数函数在声明/定义时会确定其接收的固定数量的参数,这个数量可以是从0到编译器支持的任何荒谬的大数字。使用()声明的函数接收固定但未指定数量的参数,而对应的定义则确定了实际的参数数量和类型。这是一个过时的特性。与之相反,变参函数(例如printf)在声明/定义时使用, ...,它接受N个固定参数以及0个或多个省略号(...)。 - Keith Thompson
3
有些人声称typedef的“未指定参数数量”方面是C语言中过时的特征,这是“糟糕”的一个原因。与此同时,“修复”它可能意味着消除调用任意动态链接函数的能力(或者意味着用更冗长的东西来替换它,这可能会损坏L1缓存)。 - rdm
显示剩余7条评论
3个回答

13

AF 是一个函数指针的 typedef 类型。具体来说,AF 是指向一个参数数量未指定、返回值类型为 A 的函数的指针。


啊,当然。在 V 的上下文中也是有意义的,因为它们是处理 A 并返回 A 的函数。谢谢。系统允许时我会接受这个答案。 - Dan Bron
这是一个没有参数的函数指针。具有可变数量参数的函数指针使用 ... 语法。 - rlbond
@rlbond 不,一个没有参数的函数在参数列表中有(void);那应该是typedef A (*AF)(void)。答案是正确的:它具有未指定数量的参数。 - Filipe Gonçalves
@rlbond:使用()声明的函数与使用, ...声明的可变参数函数非常不同。前者意味着您仍然必须传递与定义匹配的参数,但编译器不会检测错误(这是一种过时的功能)。后者意味着函数可以合法地接受不同数量和类型的参数;printf是最常见的例子。 - Keith Thompson
1
AF 不是一个“指针”,而是一种类型。请尽量保持准确。 - alk
@alk 谢谢。将“是一个指针”更改为“指向一个指针”。 - dbush

13
如前所述,AF(数组函数)是指返回A(数组对象指针)的函数指针。
V的定义中(即函数对象),有两个AFv1是单目函数实现的指针,v2是二元函数的指针。如果V表示运算符(副词),那么v1v2仍然分别是单目和二元实现,但也可以使用fgh来保存左侧和/或右侧参数(柯里化)。mrlrrr分别是单目秩、左侧秩和右侧秩。而id则保存了一个操作码,这样就可以从结构中恢复可打印的表示形式。
如果fgh中的任何操作数本身是动词,则它们的V结构将位于*f的f->k字节之后,对于g和h分别如此,就像所有“有效负载数据”一样。
我发现一个非常有用的链接,可以帮助理解J实现中的基本类型:Roger Hui BAA talk notes(2.69M扫描pdf)。完整的写作在Implementation of J中(html)。您还可能会发现我的原始克隆很有教育意义。同样,请参见我在这里这里提出的问题。

太棒了,非常符合我的需求(我对fgh感到好奇)。谢谢。我会查看BAA笔记和你的克隆。感谢帮助。 - Dan Bron
我接受了你的答案,尽管它比其他答案晚了一些,因为它包含了最符合我的项目需求的详细信息(值得一提的是,我已经给所有发布的答案点了赞)。 - Dan Bron

12

让我们忽略 A 实际上是什么。你现在有:

typedef int (*AF)();

AF是一个函数指针,它接受任意数量的参数并返回一个int。显然,通过将int替换为A,内容基本相同,只有返回类型不同。因此最终结果将AF标识为函数指针,该函数指针接受任意数量的参数并返回A,即匿名结构体的指针别名。

有一个有趣的网站可帮助将复杂的声明转换为人类可读的文本。


太好了。特别感谢提供cdecl.org的链接:我在这个项目中可能会需要它。 - Dan Bron
4
@DanBron: 还有一个称为 cdecl 的程序可以安装。对于Linux系统,只需安装 cdecl 包即可。对于其他操作系统,您可能需要从源代码构建该程序。 - Keith Thompson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接