typedef function pointer

C

Cancerbero

Hi (first, excuse me for my bad english)

As I know, the semantics for typedef is:

typedef A B;

I think this makes B a synonym of A, where A is an existing data type. Is
that right?

Based on the previous definition of typedef, I can't understand the next:

typedef int (*TypeFunc) (int, int);

I think it's declaring a new type called TypeFunc. The objects of that
type are functions returning int and accepting two integer parameters.
But I can't understand the semantic of the last expresion. Based on the
first definition, the last should be:

typedef int (*) (int, int) TypeFunc;
/* first the existing datatype (pointer to function) and then the new
identifier datatype. */

Well, as you can see, I really can't understand the logic of the
semantics of typedef....

Thanks
 
J

Jens.Toerring

Cancerbero said:
As I know, the semantics for typedef is:
typedef A B;
I think this makes B a synonym of A, where A is an existing data type. Is
that right?

Only in the most simple cases, so not really;-)
Based on the previous definition of typedef, I can't understand the next:
typedef int (*TypeFunc) (int, int);
I think it's declaring a new type called TypeFunc. The objects of that
type are functions returning int and accepting two integer parameters.

That's correct if you replace 'functions' by 'pointers to functions'.
And it defines just a new identifier for a type, not a new type (because
'pointer to function returning int and taking two int arguments' isn't
a new type, all you do is creating a new name for it).
But I can't understand the semantic of the last expresion. Based on the
first definition, the last should be:
typedef int (*) (int, int) TypeFunc;
/* first the existing datatype (pointer to function) and then the new
identifier datatype. */

But your first definition was too restrictive. It is as if you were
saying that a definition of a variable 'v' of type A always has the
form

A v;

But while that holds in some cases, it doesn't cover cases like a
definition of a function pointer, which you have to define like this

int ( * func_ptr ) ( int, int );

making 'func_ptr' a pointer to a function returning int and taking
two int arguments.

Now, if you compare that to the typedef you are worried about

typedef int ( * TypeFunc ) ( int, int );

you immediately see that a better description of the syntax of typedef
is that the new name you want to typedef goes in the place where in a
variable definition with that type the name of the variable would appear.

Another example would be a typedef for an array type, e.g. an array
of 10 ints. You would define such an array 'x' as

int x[ 10 ];

so, consequently, the typedef for an array of 10 ints must look
like this:

typedef int arr_of_ten_ints[ 10 ];

Regards, Jens
 
K

Keith Thompson

Cancerbero said:
Hi (first, excuse me for my bad english)

As I know, the semantics for typedef is:

typedef A B;

I think this makes B a synonym of A, where A is an existing data type. Is
that right?

That's the syntax, not the semantics. "Syntax" refers to the way a
construct is written in C source; "semantics" refers to what it means.
(And actually that's not the syntax of a typedef, except in the
simplest cases.)

As Jens points out, it's like saying that the syntax of an object
declaration is
A v;
where v is the object name and A is the type. But if you wnat v
to be an array of 20 ints, the declaration is
int v[20];
which doesn't fit the simple "A v;" syntax.

But yes, "typedef A B;" makes B a synonym of A. That's the semantics.
Based on the previous definition of typedef, I can't understand the next:

typedef int (*TypeFunc) (int, int);

Syntactically, "typedef" is treated as a storage-class specifier, like
"extern", "static", "auto", or "register". It really isn't one (it
doesn't specify any kind of storage class), but it turned out to be
convenient to define the syntax that way (though one could argue that
it's not really all that convenient after all). So if you can
understand that

extern int (*Typefunc) (int, int);

declares an external pointer object called "Typefunc", that points
to a function taking to int arguments and returning it, then you can
understand that

typedef int (*Typefunc) (int, int);

declares a type name called "Typefunc", that refers to a pointer to a
function taking to int arguments and returning it.

Now it's just a matter of understanding C's declaration syntax.
Unfortunately, that's a non-trivial task.

The basic principle is that the declaration of an entity mirrors the
use of that entity. For example:
int *a;
declares a as a pointer to int. You can also think of it as declaring
that "*a" is an int.

Dropping the extern/typedef and changing the name, consider:
int (*foo) (int, int);
Back off a bit and look at the declaration as a whole. It says that
(*foo) (int, int)
will yield an int value. It looks like a function call, so the stuff
before the arguments
(int, int)
has to denote a function, so
(*foo)
denotes a function, so
foo
has to be a pointer to a function. We've already seen that the
function takes two int arguments, and that it returns int, so we can
conclude that
int (*foo) (int, int);
declares foo as a pointer object, specifically as a pointer to a
function taking two int arguments and returning int.

Add "extern", and it declares foo as an extern object of the same type.

Add "typedef" instead of "extern", and it declares foo as a type name
for the same type.
 
J

John Bode

Cancerbero said:
Hi (first, excuse me for my bad english)

As I know, the semantics for typedef is:

typedef A B;

I think this makes B a synonym of A, where A is an existing data type. Is
that right?

Almost, but not quite. It works when talking about simple types and
identifiers, but breaks down for cases like what you describe below.

You need to read up on the concept of *declarators*, since they're
unique to C (and C++, and any other language directly derived from C).
The declarator introduces the name being declared and supplies
additional type information. For example, given the declaration

int *a[10];

the storage class is 'auto' (default), the type specifier is 'int',
the declarator is '*a[10]', and the identifier is 'a'. The type of
'a' is "10-element array of pointer to int"; the int-ness of 'a' is
specified through the type specifier, but the pointer-ness and
array-ness are specified through the declarator (incidentally, this is
why statements like "char* a, b;" don't work the way people think they
should; the '*' is associated with the identifier 'a', *not* the type
specifier 'char').

This is because C was designed with a "declaration mimics use"
paradigm. When you reference an item in an array, you use a subscript
operator []. When you dereference a pointer, you use the dereference
operator *. IOW, to get the int value pointed to by the 3rd array
element, you use the expression

*a[2];

which evaluates to an int type. So the idea was to make the
declaration of 'a' look the same as a reference to 'a' in the code. I
know this seemed like a good idea at the time, but in truth it makes
some operations harder than they need to be, and some declarations can
get obnoxiously difficult to write (which is where typedefs come in
handy). I've been programming in C for almost 15 years, and I didn't
*really* understand the concept until fairly recently.

What the typedef storage class does is make the *identifier* within
the declarator a synonym for an existing type. Going with the example
above, 'a' is a 10-element array of pointer to int. So the statement

typedef int *a[10];

creates a synonym for the existing type "10-element array of pointer
to int" and associates it with the identifier 'a'.
Based on the previous definition of typedef, I can't understand the next:

typedef int (*TypeFunc) (int, int);

I think it's declaring a new type called TypeFunc. The objects of that
type are functions returning int and accepting two integer parameters.
But I can't understand the semantic of the last expresion. Based on the
first definition, the last should be:

typedef int (*) (int, int) TypeFunc;
/* first the existing datatype (pointer to function) and then the new
identifier datatype. */

Reference what I said above. The *declarator* is (*TypeFunc) (int,
int), which says that the *identifier* TypeFunc is a pointer to a
function taking two int parameters. TypeFunc becomes the typedef
name.
 
D

Derrick Coetzee

Cancerbero said:
Based on the previous definition of typedef, I can't understand the next:

typedef int (*TypeFunc) (int, int);

This is one of the essential shortcomings of C - its declaration syntax,
especially for functions, mixes a variety of elements in a confusing
order. The goal, to make function type declarations resemble function
invocations, is for many people a confusion rather than an aid. You can
do much much worse, when you start talking about functions taking or
returning function pointers, or start worrying about where the * or &
goes when qualifiers abound.

In SPECS, an alternate C++ syntax designed by Damian Conway, your
typedef would look like this:

type TypeFunc : ^((int, int) -> int);

The type operator ^ means "pointer to", while X -> Y means "a function
taking X as an argument and returning Y." This is quite a bit closer to
what you suggested, and keeps the type info separate from the new
identifier. See Conway's paper for more:

http://www.csse.monash.edu.au/~damian/papers/HTML/ModestProposal.html
 
J

Joona I Palaste

This is one of the essential shortcomings of C - its declaration syntax,
especially for functions, mixes a variety of elements in a confusing
order. The goal, to make function type declarations resemble function
invocations, is for many people a confusion rather than an aid. You can
do much much worse, when you start talking about functions taking or
returning function pointers, or start worrying about where the * or &
goes when qualifiers abound.
In SPECS, an alternate C++ syntax designed by Damian Conway, your
typedef would look like this:
type TypeFunc : ^((int, int) -> int);
The type operator ^ means "pointer to", while X -> Y means "a function
taking X as an argument and returning Y." This is quite a bit closer to
what you suggested, and keeps the type info separate from the new
identifier. See Conway's paper for more:

That looks strangely like Haskell syntax. Perhaps later we will be
seeing typedefs like this:

type TypeFunc: ^(((int, int) -> int) -> (int -> int));

meaning "pointer to a function, which takes a function taking an
(int, int) and returning int, an returns a function taking an int
and returning int".
This is not currently possible in either C or C++ because they can't
manufacture new functions at run-time but it would be nice in some
new mixed-paradigm language.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top