www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Translation of C function pointer.

reply "Yao G." <yao.gomez spam.gmail.com> writes:
Hello gentlemen:

I'm trying to translate the newest SQLite C header to D, and I stumbled  
unto this gem:
 void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(void);

What's that? A function pointer that takes another function pointer as its name? I'm stuck at this and I don't know how to convert it to a D function pointer. Certainly, the inner pointer is easy:
 void (* function(sqlite3_vfs*,void*, const(char) *zSymbol) xDlSym)();

But what about the outer one? I am missing something? Thanks in advance. -- Yao G.
Sep 15 2010
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 15 Sep 2010 17:05:24 -0400, Yao G. <yao.gomez spam.gmail.com>  
wrote:

 Hello gentlemen:

 I'm trying to translate the newest SQLite C header to D, and I stumbled  
 unto this gem:
 void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(void);

What's that? A function pointer that takes another function pointer as its name? I'm stuck at this and I don't know how to convert it to a D function pointer. Certainly, the inner pointer is easy:
 void (* function(sqlite3_vfs*,void*, const(char) *zSymbol) xDlSym)();

But what about the outer one? I am missing something? Thanks in advance.

D supports C-style function pointers. See here: typedef char sqlite3_vfs; // note you can't use void as a parameter type in D void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(/*void*/); pragma(msg, typeof(xDlSym).stringof); outputs: void function() function(sqlite3_vfs*, void*, const const(char*) zSymbol) so I think it's a function pointer that takes those parameters and returns a function pointer that takes no parameters and returns nothing. -Steve
Sep 15 2010
next sibling parent reply BCS <none anon.com> writes:
Hello Steven,

 // note you can't use void as a parameter type in D
 void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(/*void*/);
 pragma(msg, typeof(xDlSym).stringof);
 outputs:
 
 void function() function(sqlite3_vfs*, void*, const const(char*)
 zSymbol)

D, now with C type un-garbleing! -- ... <IXOYE><
Sep 16 2010
next sibling parent Stewart Gordon <smjg_1998 yahoo.com> writes:
On 16/09/2010 15:06, BCS wrote:
 Hello Steven,

 // note you can't use void as a parameter type in D
 void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(/*void*/);
 pragma(msg, typeof(xDlSym).stringof);
 outputs:

 void function() function(sqlite3_vfs*, void*, const const(char*)
 zSymbol)

D, now with C type un-garbleing!

Perhaps the only excuse for keeping C-style function pointer declarations in D. But since we have htod, we could just as well use it and leave D free to get rid of this fossil that leads to a syntactic ambiguity. Except that I've just found htod has a bug meaning it rejects this code. Stewart.
Sep 16 2010
prev sibling parent Stewart Gordon <smjg_1998 yahoo.com> writes:
On 16/09/2010 15:37, Steven Schveighoffer wrote:
 On Thu, 16 Sep 2010 10:06:24 -0400, BCS <none anon.com> wrote:

 Hello Steven,

 // note you can't use void as a parameter type in D
 void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(/*void*/);
 pragma(msg, typeof(xDlSym).stringof);
 outputs:
 void function() function(sqlite3_vfs*, void*, const const(char*)
 zSymbol)

D, now with C type un-garbleing!

I'd have to say, if I wasn't able to use D to do this, it would have taken me hours to figure this one out. Even knowing what it is now, I still can't read it :)

It took me a moment as well. Basically, the C declaration ReturnType (*Name)(Parameters); becomes in D ReturnType function(Parameters) Name; Where you've got one inside another, you try to apply the same principle. So void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(void); starting with the outermost level, you end up with (note (void) becomes ()) void function() (*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol); instead of Name, you've got this funny thing. You're left with a function pointer declaration where void function() is the ReturnType, so transforming it again you get void function() function(sqlite3_vfs*, void*, char* zSymbol) xDlSym; or in D2, void function() function(sqlite3_vfs*, void*, const(char)* zSymbol) xDlSym; Whoever wrote the C declaration must have had an even harder job getting it right! I wouldn't have hesitated to use a typedef, if ever I had reason to do C stuff as complicated as this. Stewart.
Sep 16 2010
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 16 Sep 2010 10:06:24 -0400, BCS <none anon.com> wrote:

 Hello Steven,

 // note you can't use void as a parameter type in D
 void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(/*void*/);
 pragma(msg, typeof(xDlSym).stringof);
 outputs:
  void function() function(sqlite3_vfs*, void*, const const(char*)
 zSymbol)

D, now with C type un-garbleing!

I'd have to say, if I wasn't able to use D to do this, it would have taken me hours to figure this one out. Even knowing what it is now, I still can't read it :) D is a huge leap ahead of C in this regard! -Steve
Sep 16 2010
next sibling parent reply BCS <none anon.com> writes:
Hello Steven,

 On Thu, 16 Sep 2010 10:06:24 -0400, BCS <none anon.com> wrote:
 
 Hello Steven,
 
 // note you can't use void as a parameter type in D
 void (*(*xDlSym)(sqlite3_vfs*,void*, const char
 *zSymbol))(/*void*/);
 pragma(msg, typeof(xDlSym).stringof);
 outputs:
 void function() function(sqlite3_vfs*, void*, const const(char*)
 zSymbol)


taken me hours to figure this one out. Even knowing what it is now, I still can't read it :)

The trick is that function pointers are best read from the inside out. -- ... <IXOYE><
Sep 16 2010
parent reply Kagamin <spam here.lot> writes:
BCS Wrote:

 The trick is that function pointers are best read from the inside out.
 -- 

Sep 16 2010
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
Jonathan M Davis wrote:
 On Thursday 16 September 2010 23:50:16 Kagamin wrote:
 BCS Wrote:
 The trick is that function pointers are best read from the inside out.

that's why you have to use braces to give pointer higher precedence. One of the earlier books by Stroustroup gives a nice monster of arrays, pointers and functions to master understanding of declarations.

It's essentially the same principle that makes it so that the D

 int[4][3] a;

 is an array with 3 rows and 4 columns rather than 4 rows and 3 

 you'd expect.

 - Jonathan M Davis

I don't see it that D's declaration follows C's at least in array declarations: int[4] is an array of 4 ints; like Simen, let's call it U. Now U[3] is an array of 3 Us; i.e. 3 int[4]s I read that from left to right, not inside out. The equivalent C declaration has the opposite type: int a[4][3]; Now that is 4 arrays of 3 ints. D wins big time here! :) Two programs to test: #include <stdio.h> int main() { int a[4][3]; printf("%u\n", sizeof(a[0])); return 0; } Outputs 12. import std.stdio; void main() { int[4][3] a; writeln(typeof(a[0]).sizeof); } Outputs 16. Ali
Sep 17 2010
parent Jesse Phillips <jessekphillips+D gmail.com> writes:
Jonathan M Davis Wrote:

 On Friday, September 17, 2010 10:43:12 Ali Çehreli wrote:
 int[4] is an array of 4 ints; like Simen, let's call it U.
 Now U[3] is an array of 3 Us; i.e. 3 int[4]s
 
 I read that from left to right, not inside out.

No, no. You read it outwards from the variable name (which is essentially what you're doing in C), so you read it from right to left. If you read it from left to right it would be an integer of arrays, which makes no sense. It's just like how int* is a pointer to an int, not an int to a pointer. Declarations are read outwards from the variable name (which is usually right to left).

That isn't how you read it. int* b; int pointer b. int[4][3] a; int array of 4, array of 3 a. This isn't exactly grammatically clear English. But it isn't English it is D. int c[3][4]; c is array of 3 int arrays of 4 int. Definitely not left to right.
Sep 17 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday 16 September 2010 23:50:16 Kagamin wrote:
 BCS Wrote:
 The trick is that function pointers are best read from the inside out.

All C declarations are read from inside out, postfixes take precedence, that's why you have to use braces to give pointer higher precedence. One of the earlier books by Stroustroup gives a nice monster of arrays, pointers and functions to master understanding of declarations.

It's essentially the same principle that makes it so that the D declaration int[4][3] a; is an array with 3 rows and 4 columns rather than 4 rows and 3 columns like you'd expect. - Jonathan M Davis
Sep 17 2010
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
On Fri, 17 Sep 2010 10:12:34 +0200, Jonathan M Davis <jmdavisProg gmx.com>  
wrote:

 On Thursday 16 September 2010 23:50:16 Kagamin wrote:
 BCS Wrote:
 The trick is that function pointers are best read from the inside out.

All C declarations are read from inside out, postfixes take precedence, that's why you have to use braces to give pointer higher precedence. One of the earlier books by Stroustroup gives a nice monster of arrays, pointers and functions to master understanding of declarations.

It's essentially the same principle that makes it so that the D declaration int[4][3] a; is an array with 3 rows and 4 columns rather than 4 rows and 3 columns like you'd expect.

I've always been confused by C in this regard. It seems to logical to me that T[3] works the same whether T is U[4] or U. -- Simen
Sep 17 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, September 17, 2010 05:00:55 Simen kjaeraas wrote:
 On Fri, 17 Sep 2010 10:12:34 +0200, Jonathan M Davis <jmdavisProg gmx.com>
 
 wrote:
 On Thursday 16 September 2010 23:50:16 Kagamin wrote:
 BCS Wrote:
 The trick is that function pointers are best read from the inside out.

All C declarations are read from inside out, postfixes take precedence, that's why you have to use braces to give pointer higher precedence. One of the earlier books by Stroustroup gives a nice monster of arrays, pointers and functions to master understanding of declarations.

It's essentially the same principle that makes it so that the D declaration int[4][3] a; is an array with 3 rows and 4 columns rather than 4 rows and 3 columns like you'd expect.

I've always been confused by C in this regard. It seems to logical to me that T[3] works the same whether T is U[4] or U.

You're going to have to elaborate on that. I'm not quite sure what you're talking about. And the syntax int[4][3] isn't legal C anyway. It just does what C would likely have done had it put the brackets with the type rather than the variable name, since D uses pretty much the same syntax for variable declarations and therefore pretty much the same rules. - Jonathan M Davis
Sep 17 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, September 17, 2010 10:43:12 Ali =C3=87ehreli wrote:
 Jonathan M Davis wrote:
  > On Thursday 16 September 2010 23:50:16 Kagamin wrote:
  >> BCS Wrote:
  >>> The trick is that function pointers are best read from the inside ou=

  >>=20
  >> All C declarations are read from inside out, postfixes take precedenc=

  >> that's why you have to use braces to give pointer higher precedence.
  >> One of the earlier books by Stroustroup gives a nice monster of
  >> arrays, pointers and functions to master understanding of
  >> declarations.
  >=20
  > It's essentially the same principle that makes it so that the D
=20
 declaration
=20
  > int[4][3] a;
  >=20
  > is an array with 3 rows and 4 columns rather than 4 rows and 3
=20
 columns like
=20
  > you'd expect.
  >=20
  > - Jonathan M Davis
=20
 I don't see it that D's declaration follows C's at least in array
 declarations:
=20
 int[4] is an array of 4 ints; like Simen, let's call it U.
 Now U[3] is an array of 3 Us; i.e. 3 int[4]s
=20
 I read that from left to right, not inside out.

No, no. You read it outwards from the variable name (which is essentially w= hat=20 you're doing in C), so you read it from right to left. If you read it from = left=20 to right it would be an integer of arrays, which makes no sense. It's just = like=20 how int* is a pointer to an int, not an int to a pointer. Declarations are = read=20 outwards from the variable name (which is usually right to left).
=20
 The equivalent C declaration has the opposite type:
=20
      int a[4][3];
=20
 Now that is 4 arrays of 3 ints.
=20
 D wins big time here! :)

Again, you're reading outwards from the variable name. That means that you = read=20 this one left to right, though it gets a bit weird because the type is on b= oth=20 sides of the variable name (though you get the same problem with function=20 pointers). Both int[3][4] a; and int a[4][3]; are 4 arrays of 3 ints, and both read outwards from the variable name. And= =20 because when you index them, the max indices would be a[3][2], it totally t= hrows=20 people off to declare them the D way because the order is reversed from whe= re it=20 was declared (since you're using the brackets on the opposite side of the=20 variable name now). The fact that int[3][4] a; is 4 arrays of 3 ints is _exactly_ the same as h= ow it=20 works with C declarations. You read outward from the variable name. =2D Jonathan M Davis
Sep 17 2010
prev sibling next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Jonathan M Davis <jmdavisProg gmx.com> wrote:

 I've always been confused by C in this regard. It seems to logical to me
 that T[3] works the same whether T is U[4] or U.

You're going to have to elaborate on that. I'm not quite sure what you're talking about. And the syntax int[4][3] isn't legal C anyway. It just does what C would likely have done had it put the brackets with the type rather than the variable name, since D uses pretty much the same syntax for variable declarations and therefore pretty much the same rules.

You know, after reading your post to Ali, and trying to come up with a reason why I felt the way I did, I have found enlightenment. Limited, yes, but I now see that C's order is also good. Now if only there were a reasonable way to extricate the type from the variable name... -- Simen
Sep 17 2010
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Friday, September 17, 2010 17:07:15 Simen kjaeraas wrote:
 Jonathan M Davis <jmdavisProg gmx.com> wrote:
 I've always been confused by C in this regard. It seems to logical to me
 that T[3] works the same whether T is U[4] or U.

You're going to have to elaborate on that. I'm not quite sure what you're talking about. And the syntax int[4][3] isn't legal C anyway. It just does what C would likely have done had it put the brackets with the type rather than the variable name, since D uses pretty much the same syntax for variable declarations and therefore pretty much the same rules.

You know, after reading your post to Ali, and trying to come up with a reason why I felt the way I did, I have found enlightenment. Limited, yes, but I now see that C's order is also good. Now if only there were a reasonable way to extricate the type from the variable name...

Well, it's easy to get the type in D, but C is not so enlightened. That's what happens when you compare languages which have about a 25 year difference in age. - Jonathan M Davis
Sep 17 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 15 Sep 2010 17:15:12 -0400, Steven Schveighoffer  
<schveiguy yahoo.com> wrote:

 On Wed, 15 Sep 2010 17:05:24 -0400, Yao G. <yao.gomez spam.gmail.com>  
 wrote:

 Hello gentlemen:

 I'm trying to translate the newest SQLite C header to D, and I stumbled  
 unto this gem:
 void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(void);

What's that? A function pointer that takes another function pointer as its name? I'm stuck at this and I don't know how to convert it to a D function pointer. Certainly, the inner pointer is easy:
 void (* function(sqlite3_vfs*,void*, const(char) *zSymbol) xDlSym)();

But what about the outer one? I am missing something? Thanks in advance.

D supports C-style function pointers. See here: typedef char sqlite3_vfs; // note you can't use void as a parameter type in D void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(/*void*/); pragma(msg, typeof(xDlSym).stringof); outputs: void function() function(sqlite3_vfs*, void*, const const(char*) zSymbol)

BTW, not sure why the const const(char*)... -Steve
Sep 15 2010
prev sibling parent "Yao G." <yao.gomez spam.gmail.com> writes:
On Wed, 15 Sep 2010 16:15:12 -0500, Steven Schveighoffer  
<schveiguy yahoo.com> wrote:

 D supports C-style function pointers.  See here:

 typedef char sqlite3_vfs;

 // note you can't use void as a parameter type in D
 void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(/*void*/);
 pragma(msg, typeof(xDlSym).stringof);

 outputs:

 void function() function(sqlite3_vfs*, void*, const const(char*) zSymbol)

 so I think it's a function pointer that takes those parameters and  
 returns a function pointer that takes no parameters and returns nothing.

 -Steve

Thanks Steve! -- Yao G.
Sep 15 2010