Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I interpret this declaration that appears to be a function declaration, but doesn't fit the usual mould?

I'm trying to decipher this declaration from sqlite3.c

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

It seems like it is declaring a function because subsequently there is this

SQLITE_PRIVATE void (*sqlite3OsDlSym(sqlite3_vfs *pVfs, void *pHdle, const char *zSym))(void){
  return pVfs->xDlSym(pVfs, pHdle, zSym);
}

and then what appear to be calls to the function

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

and

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

But I cannot make sense of the declaration. I've highlighted what I cannot understand

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

I'm wondering why the declaration is not like so

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

I expect that there may well be a similar question already asked but searching for terms like (, ) and void doesn't really get anywhere. So, if this is a dupe, I'd be very happy for it to be closed as such.

like image 886
David Heffernan Avatar asked Aug 15 '17 21:08

David Heffernan


1 Answers

This is declaring a function that returns a function pointer. The return type is void (*)(void) (SQLITE_PRIVATE expands to static and is not part of the return type, per comments), but the function name (and parameters) have to appear inside the (*) part.

Functions and arrays are the two C type categories that require to do gymnastics to parse. You can think of array types and function types as "decorating" the identifier that they describe. If you write int foo, you're saying that the symbol "foo" has an integer type. If you write int foo(double), you're saying that the symbol foo(double) has an integer type. foo and (double) have to stick together, so any further decoration has to wrap the entire thing as if it was a single name.

The point is best illustrated by mixing array types and function types, even though the end type might not be legal in C. (That says a lot about how ridiculous the syntax is.) For instance:

int foo[5](double)

would be an array (foo[5]) of functions (int ... (double)). On the other hand:

int foo(double)[5]

is a function (foo(double)) and returns an array (int ... [5]).

The external resource cdecl.org can help you make sense of this kind of declaration. However, you need to replace the structure names with standard types (or write structure types as struct sqlite_vfs instead of just sqlite_vfs) for it to understand your declaration.

like image 172
zneak Avatar answered Sep 27 '22 19:09

zneak