Как я интерпретирую это объявление, которое кажется объявлением функции,но не соответствует обычной форме?


Я пытаюсь расшифровать это объявление из 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);

И

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

2 ответа:

Это объявление функции, которая возвращает указатель на функцию. Тип возвращаемого значения:void (*)(void) (SQLITE_PRIVATE расширяется до static и не является частью возвращаемого типа, согласно комментариям), но имя функции (и параметры) должны появиться внутри части (*).

Функции и массивы - это две категории типа C, которые требуют выполнения гимнастики для синтаксического анализа. Типы массивов и типы функций можно рассматривать как "украшение" идентификатора, который они описывают. Если вы пишете int foo, Вы говорите, что символ " foo " имеет целочисленный тип. Если вы пишете int foo(double), вы говорите, что символ foo(double) имеет целочисленный тип. foo и (double) должны держаться вместе, поэтому любое дальнейшее украшение должно обернуть всю вещь, как если бы это было одно имя.

Этот момент лучше всего иллюстрируется смешиванием типов массивов и типов функций, даже если конечный тип может быть нелегальным в C. (Это говорит о том, насколько нелеп синтаксис.) Например:
int foo[5](double)

Будет массивом (foo[5]) функций (int ... (double)). С другой стороны:

int foo(double)[5]

Является функцией (foo(double)) и возвращает массив (int ... [5]).

Внешний ресурс cdecl.org может помочь вам понять смысл такого рода заявлений. Однако вам нужно заменить имена структур стандартными типами (или написать типы структур как struct sqlite_vfs вместо просто sqlite_vfs), чтобы он понял ваше объявление.

Это заявление

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

Сначала функция f объявляется с помощью typedef, а затем без typedef

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