这个声明看起来像是一个函数声明,但不符合通常的模式。我该如何解释它?

8
我正在尝试解读sqlite3.c文件中的这个声明。
SQLITE_PRIVATE void (*sqlite3OsDlSym(sqlite3_vfs *, void *, const char *))(void);

这似乎是在声明一个函数,因为随后有这个内容。
SQLITE_PRIVATE void (*sqlite3OsDlSym(sqlite3_vfs *pVfs, void *pHdle, const char *zSym))(void){
  return pVfs->xDlSym(pVfs, pHdle, zSym);
}

然后似乎是对该函数的调用。
xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry);

and

xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry);

但我无法理解这个声明。我已经把我无法理解的部分标出了。
SQLITE_PRIVATE void (*sqlite3OsDlSym(sqlite3_vfs *, void *, const char *))(void);
                    ^                                                    ^^^^^^^

我在想为什么声明不像这样。
SQLITE_PRIVATE void *sqlite3OsDlSym(sqlite3_vfs *, void *, const char *);

我预计可能已经有类似的问题被提出,但是搜索类似于 ()void 的术语并没有什么进展。所以,如果这是一个重复的问题,我很乐意将其关闭。
2个回答

8
这是声明一个返回函数指针的函数。返回类型为void (*)(void) (SQLITE_PRIVATE代表static且不属于返回类型,参见注释),但函数名(和参数)必须出现在(*)部分内。
函数和数组是C语言中需要特殊处理的两种类型。你可以将数组类型和函数类型视为装饰符,用来描述它们所标识的标识符。如果你写了int foo,那么就说明符号"foo"具有整数类型。如果写成int foo(double),那么就说明符号foo(double)具有整数类型。由于foo(double)必须粘在一起,所以任何进一步的修饰都必须将整个东西包装起来,就像它是一个单独的名称一样。
最好通过混合数组类型和函数类型来说明这一点,即使最终的类型可能在C中不合法。(这说明了语法有多么荒谬。)例如:
int foo[5](double)

将会是一个函数数组(foo[5]),其中每个函数都接受一个double类型的参数并返回一个int类型的值。另一方面:

int foo(double)[5]

这是一个函数(foo(double)),返回一个数组(int ... [5])。

外部资源cdecl.org可以帮助您理解这种声明。但是,为了让它理解您的声明,您需要将结构名称替换为标准类型(或将结构类型写为struct sqlite_vfs而不仅仅是sqlite_vfs)。


谢谢,我尝试了cdecl.org,但它只给了我一个“语法错误”的提示。现在我明白了,那是因为它无法识别sqlite3_vfs。如果我只是用int替换sqlite3_vfs,那么我就可以得到答案了。 - David Heffernan
另外一个让我困惑的问题是,虽然sqlite3OsDlSym返回“指向函数(无返回值)的指针”,但实际返回的函数指针具有不同的原型,因此需要进行(sqlite3_loadext_entry)强制转换。 - David Heffernan
根据SQLITE_PRIVATE的实际情况,它可能适用于被声明的函数而不是返回类型(例如,如果它是static的宏)。 - M.M
SQLITE_PRIVATE 扩展为 static,我相信。 - David Heffernan

2
这个声明
SQLITE_PRIVATE void (*sqlite3OsDlSym(sqlite3_vfs *, void *, const char *))(void);

这是一个函数声明,其返回类型是指向特定类型的函数指针。

void ( * )( void )

声明可以通过引入typedef进行简化。例如:
typedef void ( *FP )( void );

SQLITE_PRIVATE  FP sqlite3OsDlSym(sqlite3_vfs *, void *, const char *);

这里有一个演示程序,它使用类似的函数返回指向另一个函数的指针。
#include <stdio.h>

typedef void ( *FP )( void );

void h( void )
{
    puts( "Hello World" );
}

FP f( void );
void ( *f( void) )( void )
{
    return h;
}

int main(void) 
{
    f()();

    return 0;
}

它的输出结果是

Hello World

首先,使用typedef声明函数f,然后在没有typedef的情况下声明。

FP f( void );
void ( *f( void) )( void )
{
    return h;
}

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