typedef procedure

A

aleksa

typedef void (*PROC) (void); // v1
typedef void (PROC) (void); // v2

void foo (PROC callme)
{
callme();
}

Do I use V1 or V2 when defining PROC?
Both seem to work...

TIA
 
J

John Bode

but, this form looks more ugly...

there is no reason to make things more ugly than they need to be...

we could just as easily imagine that this were some-other-language, where
functions typically are first-class, and most objects are reference-types
without explicit pointer marks...

then, there is no confusion about the function pointer, they just take
something and call it...- Hide quoted text -

- Show quoted text -

Bitter experience has taught me that hiding a pointer behind a typedef
inevitably leads to heartburn[1]. Eventually someone forgets they're
dealing with a pointer type and tries to use '&' when they don't need
to, or attempts to use '.' when they meant '->', or forgets that they
need to use '*' before passing it to another function, etc. Unless
it's something you will never have to dereference (either explicitly
with * or implicitly with -> or []), then IME it's best to explicitly
declare the object as a pointer.

1. In C, anyway; I am slowly learning that C++ is a very different
animal in this regard, especially when it comes to writing templates,
although I've seen this same problem bite other people in the ass in C+
+.
 
B

Ben Bacarisse

aleksa said:
typedef void (*PROC) (void); // v1
typedef void (PROC) (void); // v2

void foo (PROC callme)
{
callme();
}

Do I use V1 or V2 when defining PROC?
Both seem to work...

They do, yes. I'd go a third way! The trouble with v1 is that is hides
the fact the PROC is a pointer type. Many people have found that this
can be troublesome later, but it is fair to say that it is at its "least
bad" with function types because there is so little you can do with
them. None the less, I'd use v2 but without ALL CAPS (all caps is for
MACROS in my book) and without the extra parentheses:

typedef void Proc(void);

However, I'd then write:

void foo (Proc *callme)
{
callme();
}

so that the fact that a pointer is being passed is obvious. Function
types in parameter lists are converted to pointer-to-function types but
it's clearer, in my view, if you make the pointer explicit.

I learnt C when one had to write (*callme)() but I've grown to prefer
callme().
 
K

Keith Thompson

pete said:
aleksa said:
typedef void (*PROC) (void); // v1
typedef void (PROC) (void); // v2

void foo (PROC callme)
{
callme();
}

Do I use V1 or V2 when defining PROC?
Both seem to work...

It's analagous to the difference between
void foo(char *array);
and
void foo(char array[]);

Yes, it is ...
The only thing that you can do with an expression of function type
in statement in a correct C program, is to derive a pointer from it.

An expression of function type will always convert to pointer,
unless it is the operand of the adress operator,
in which case the result is a pointer,
or unless it is the operand of the sizeof operator,
in which case you do not have a correct C program.

.... but not for that reason. As with arrays and pointers, there are two
independent rules regarding functions and pointers. One rule is about
the compile-time meaning of a parameter declaration; the other is about
implicit conversion of expressions of function type.

C99 6.7.5.3p7:

A declaration of a parameter as ‘‘array of _type_’’ shall be adjusted
to ‘‘qualified pointer to _type_’’, [...]

and p8:

A declaration of a parameter as ‘‘function returning _type_’’ shall
be adjusted to ‘‘pointer to function returning _type_’’, [...]

C99 6.3.2.1p3:

Except when [exceptions skipped], an expression that has type
‘‘array of _type_’’ is converted to an expression with type
‘‘pointer to _type_’’ that points to the initial element of the
array object and is not an lvalue.

and p4:

A _function designator_ is an expression that has function
type. Except when it is the operand of the sizeof operator or the
unary & operator, a function designator with type ‘‘function
returning type’’ is converted to an expression that has type
‘‘pointer to function returning type’’.

It's 6.7.5.3, not 6.3.2.1, that applies to the OP's code.
 
T

Tim Rentsch

Ben Bacarisse said:
They do, yes. I'd go a third way! The trouble with v1 is that is hides
the fact the PROC is a pointer type. Many people have found that this
can be troublesome later, but it is fair to say that it is at its "least
bad" with function types because there is so little you can do with
them. None the less, I'd use v2 but without ALL CAPS (all caps is for
MACROS in my book) and without the extra parentheses:

typedef void Proc(void);

However, I'd then write:

void foo (Proc *callme)
{
callme();
}

so that the fact that a pointer is being passed is obvious. Function
types in parameter lists are converted to pointer-to-function types but
it's clearer, in my view, if you make the pointer explicit.

I understand you're expressing what is in essence just a personal
opinion. Still I would like to ask for some amount of explanation
or elaboration. Personally I don't see any value to using 'Foo *f'
instead of 'Foo f' in cases like this when 'f' is to be of a pointer
to function type. Can you shed some light on your views?
 
T

Tim Rentsch

John Bode said:
Bitter experience has taught me that hiding a pointer behind a typedef
inevitably leads to heartburn.

What experience(s) have you had in this regard with pointer-to-
function types for function parameters?
Eventually someone forgets they're
dealing with a pointer type and tries to use '&' when they don't need
to, or attempts to use '.' when they meant '->', or forgets that they
need to use '*' before passing it to another function, etc.

Won't all of these be caught by the compiler for pointer-to
function arguments? (I admit I'm assuming the presence of
function prototypes, but these days anyone who doesn't use
function prototypes essentially always seems to be just
asking for trouble anyway.)
Unless
it's something you will never have to dereference (either explicitly
with * or implicitly with -> or []), then IME it's best to explicitly
declare the object as a pointer.

You mean, like not having to derefence a pointer-to-function,
because it's dereferenced automatically whenever it's used
to call a function? It seems to me that there is _never_
any need to use some sort of dereferencing operator in
conjunction with a pointer-to-function. Of course, some
people may prefer to write '(*foo)()' rather than just 'foo()',
but that seems more like choice than necessity. Is that
different from your experience/view on the subject?
 
B

Ben Bacarisse

Tim Rentsch said:
Ben Bacarisse <[email protected]> writes:

I understand you're expressing what is in essence just a personal
opinion. Still I would like to ask for some amount of explanation
or elaboration. Personally I don't see any value to using 'Foo *f'
instead of 'Foo f' in cases like this when 'f' is to be of a pointer
to function type. Can you shed some light on your views?

Not really! It's largely habit formed from history. The C I learnt
(K&R C) did not have the automatic conversion of a parameter from
function type to pointer to function type (though it did have that
conversion for array types). Also, a function was called by writing a
function-valued expression before the ()s not a pointer-to-function
expression as now. Hence one had to write:

void foo()
Proc *callme;
{
(*callme)();
}

Whilst I appreciate the simplification of having a pointer-to-function
expression for calling, I've not internalised the conversion in the
parameter list, so I prefer to see it for what it is rather than rely on
the conversion.

You say you don't see any value in using Foo *f. Fair enough. Do you
see any value in preferring Foo f? I had a narrow preference for the
explicit nature of Foo *f and I can't see any reason to drop the * (I am
certain neither of us values fewer keystrokes for the sake of it).
 
B

Ben Bacarisse

Tim Rentsch said:
John Bode <[email protected]> writes:
Unless
it's something you will never have to dereference (either explicitly
with * or implicitly with -> or []), then IME it's best to explicitly
declare the object as a pointer.

A function pointer is one such beast. You never have to dereference it,
either implicitly of explicitly.
You mean, like not having to derefence a pointer-to-function,
because it's dereferenced automatically whenever it's used
to call a function?

It isn't -- not anymore.
It seems to me that there is _never_
any need to use some sort of dereferencing operator in
conjunction with a pointer-to-function. Of course, some
people may prefer to write '(*foo)()' rather than just 'foo()',
but that seems more like choice than necessity. Is that
different from your experience/view on the subject?

Since all functions are now (post 1990) called through a pointer, adding
the * to the call is obfuscation. The pointer gets converted to a
function value which "decays" back to a pointer for the call.
 
N

Nick Keighley

ugliness is int he eye of the beholder. I;m almost sold on Richard's
way of doing it. THough I don't like all upper case typedefs. And I
think function pointers are sufficiently unusual to resort to mild
Hungarian (<spit>)

fixing the poor layout as well, we have...

typedef void Callback_function (void);

void foo (Callback_function* callme)
{
callme ();
}


I don't bother with the fancy call syntax


yes we could but we aren't programming in that language we are
programming in C

(define foo (lambda (callme) (callme)))


so what... Could you give an example that illustrates your point. You
can't really call someone's code "ugly" if you won't produce your own,
beautiful, code.
Bitter experience has taught me that hiding a pointer behind a typedef
inevitably leads to heartburn[1].


I'd make an exception for function pointers (though I do go a bit
hungarian)
 Eventually someone forgets they're
dealing with a pointer type and tries to use '&' when they don't need
to, or attempts to use '.' when they meant '->',

not with a fucntion pointer they don't
or forgets that they
need to use '*' before passing it to another function, etc.  Unless
it's something you will never have to dereference (either explicitly
with * or implicitly with -> or []), then IME it's best to explicitly
declare the object as a pointer.

yes, but none of this applies to FPs
1.  In C, anyway; I am slowly learning that C++ is a very different
animal in this regard, especially when it comes to writing templates,
although I've seen this same problem bite other people in the ass in C+
+.

templates are the work of the devil
 
T

Tim Rentsch

Ben Bacarisse said:
Not really! It's largely habit formed from history. The C I learnt
(K&R C) did not have the automatic conversion of a parameter from
function type to pointer to function type (though it did have that
conversion for array types). Also, a function was called by writing a
function-valued expression before the ()s not a pointer-to-function
expression as now. Hence one had to write:

void foo()
Proc *callme;
{
(*callme)();
}

Whilst I appreciate the simplification of having a pointer-to-function
expression for calling, I've not internalised the conversion in the
parameter list, so I prefer to see it for what it is rather than rely on
the conversion.

You say you don't see any value in using Foo *f. Fair enough. Do you
see any value in preferring Foo f? I had a narrow preference for the
explicit nature of Foo *f and I can't see any reason to drop the * (I am
certain neither of us values fewer keystrokes for the sake of it).

Like you, I originally learned C from K&R, with the (*f)() syntax
for calling through function pointers. I like the new syntax
rule, mostly because calls look cleaner.

I prefer using the 'Foo f' declaration, rather than 'Foo *f', for
several different reasons. Here are some (I'm not claiming
the list is exhaustive just yet):

1. ISO C has eliminated most of the difference between a function
type and a pointer to function type. I think removing this
distinction (which is somewhat artificial) is an improvement in
C, and using 'Foo f' is some movement in that direction.

2. Following the C rule that "declaration mimics use", using 'Foo *f'
seems wrong, because I certainly don't write '*f()', but '(*f)()'
looks like it doesn't match the declaration either.

3. If I need to have a parameter that is a pointer to a pointer
to a function, it seems better to use only one '*' in the
declaration, because those cases will really /need/ the '*';
for example, '*fp = call_back', or '(*fp)()'. Because I write
calls through plain pointer-to-function as 'f()', normally
I would write calls through pointer-to-pointer-to-function
as '(*fp)()', not '(**fp)()'.

4. If given a choice, I would like to indicate somehow that some
variable is a (pointer to) a function, but usually I would do this
using the type name, eg, 'XYZ_callback_f blah', with the '_f'
meaning function (or pointer to function).

Summarizing: I don't find that the '*' adds anything, except
it does add some confusion; conversely, leaving out the '*'
seems to fit better with the new rules for how functions
and pointers-to-function behave, and I've embraced that
direction.

So for what it's worth, those are my thoughts on the matter.
 
B

Ben Bacarisse

Tim Rentsch said:
Like you, I originally learned C from K&R, with the (*f)() syntax
for calling through function pointers. I like the new syntax
rule, mostly because calls look cleaner.

I prefer using the 'Foo f' declaration, rather than 'Foo *f', for
several different reasons. Here are some (I'm not claiming
the list is exhaustive just yet):

1. ISO C has eliminated most of the difference between a function
type and a pointer to function type. I think removing this
distinction (which is somewhat artificial) is an improvement in
C, and using 'Foo f' is some movement in that direction.

I agree with this one but not quite enough to break the habit (yet)!
2. Following the C rule that "declaration mimics use", using 'Foo *f'
seems wrong, because I certainly don't write '*f()', but '(*f)()'
looks like it doesn't match the declaration either.

This is not, for me, a strong argument. I don't think there is a "rule"
that declaration follows use but if there is it is often broken: the
operators ., ->, [] and () all mess it up to some extent. A C
programmer simply has to know what there operators do and the fact that
one of them -- function call -- can be tidied up by sticking to a
particular convention in the declaration of function parameters is not
much of a gain.

One could argue that there is at least as much asymmetry in the fact
that

Func f;

and

void doit(Func f);

exhibit quite different meanings for apparently similar declarations.
I.e. while your usage reduces surprise in one quarter, it can introduce
it in another because if you want an object with the same type as the
parameter, the * is required.
3. If I need to have a parameter that is a pointer to a pointer
to a function, it seems better to use only one '*' in the
declaration, because those cases will really /need/ the '*';
for example, '*fp = call_back', or '(*fp)()'. Because I write
calls through plain pointer-to-function as 'f()', normally
I would write calls through pointer-to-pointer-to-function
as '(*fp)()', not '(**fp)()'.

Unless I've misunderstood you we must be talking about different things
here. The context was that we have a function type (Func, say) and we
are discussing the merits of

void doit(Func f);

vs.

void doit(Func *f);

In this context, I don't see how you can have just one * when the
parameter is a pointer to a function pointer. Maybe you are thinking
about a related matter: hiding the pointer in the function typedef?

If anything, your point 3 is a case for my usage. The distinction
between Func *f and Func **f is clear and unsurprising, but having to
switch from Func f to Func **f when adding just one level of indirection
is surely a source of potential confusion?
4. If given a choice, I would like to indicate somehow that some
variable is a (pointer to) a function, but usually I would do this
using the type name, eg, 'XYZ_callback_f blah', with the '_f'
meaning function (or pointer to function).

I don't see how this relates to the declaration. Are you saying that
having both an indicative name and a * in the declaration is overkill?
I am quite happy to have both.
Summarizing: I don't find that the '*' adds anything, except
it does add some confusion; conversely, leaving out the '*'
seems to fit better with the new rules for how functions
and pointers-to-function behave, and I've embraced that
direction.

I can see your point, but I don't find that the * adds much significant
confusion. There are cases where leaving it out can also be seen as
confusing though I grant that they are rare enough that they can
probably be discounted.
So for what it's worth, those are my thoughts on the matter.

Likewise. I was away for a week and I fear that this minor topic might
be being extended beyond its significance but your considered response
deserved some reply.
 
T

Tim Rentsch

Ben Bacarisse said:
Tim Rentsch said:
Like you, I originally learned C from K&R, with the (*f)() syntax
for calling through function pointers. I like the new syntax
rule, mostly because calls look cleaner.

I prefer using the 'Foo f' declaration, rather than 'Foo *f', for
several different reasons. Here are some (I'm not claiming
the list is exhaustive just yet):

1. ISO C has eliminated most of the difference between a function
type and a pointer to function type. I think removing this
distinction (which is somewhat artificial) is an improvement in
C, and using 'Foo f' is some movement in that direction.

I agree with this one but not quite enough to break the habit (yet)!
2. Following the C rule that "declaration mimics use", using 'Foo *f'
seems wrong, because I certainly don't write '*f()', but '(*f)()'
looks like it doesn't match the declaration either.

This is not, for me, a strong argument. [snip elaboration]

Oh, I wasn't meaning to make an argument, just explain my
own thoughts on the matter. I wasn't trying (or expecting)
to convince anyone.
One could argue that there is at least as much asymmetry in the fact
that

Func f;

and

void doit(Func f);

exhibit quite different meanings for apparently similar declarations.
I.e. while your usage reduces surprise in one quarter, it can introduce
it in another because if you want an object with the same type as the
parameter, the * is required.

Oops, there is a bit of confusion here that I should clear
up. My intention is that the type 'Func' include the pointerness
of pointer-to-function (eg, 'typedef void (*Func)(int)').
I rarely define actual function types, since they are almost
never the types the program needs.

Unless I've misunderstood you we must be talking about different things
here. The context was that we have a function type (Func, say) and we
are discussing the merits of

void doit(Func f);

vs.

void doit(Func *f);

In this context, I don't see how you can have just one * when the
parameter is a pointer to a function pointer. Maybe you are thinking
about a related matter: hiding the pointer in the function typedef?

As above, I do mean putting the pointerness in the function typedef,
although I don't think of it as "hiding".
If anything, your point 3 is a case for my usage. The distinction
between Func *f and Func **f is clear and unsurprising, but having to
switch from Func f to Func **f when adding just one level of indirection
is surely a source of potential confusion?

Yes, and I might list that as a reason for putting the
function-pointerness in the typedef for 'Func'. Normally
I think it's a good idea to avoid actual function types
for function parameters -- too many chances for some
confusion between pre-adjusted and post-adjusted types.

I don't see how this relates to the declaration. Are you saying that
having both an indicative name and a * in the declaration is overkill?
I am quite happy to have both.

I am meaning to make an orthogonal statement. Or, to say that
another way, I don't want to have to depend on the '*' to
indicate a function parameter. So function type names (usually
pointer-to-function, but actual function types also) normally
should have some sort of indicator in the type name to show
the functionness.

I can see your point, but I don't find that the * adds much significant
confusion.

Yes, "confusion" is probably not quite the right term;
"cognitive load", perhaps. Whatever the word I agree
the magnitude is small, although for me it is definitely
non-zero.
There are cases where leaving it out can also be seen as
confusing though I grant that they are rare enough that they can
probably be discounted.

Right. It would be nice to do an actual, controlled experiment
to try to measure these things, rather than having to rely on
personal or anecdotal experience. My sense is that changes
like this are often sea changes, and it's hard to see results
in isolation. However I don't have any sort of hard data to
back that up.

Likewise. I was away for a week and I fear that this minor topic might
be being extended beyond its significance but your considered response
deserved some reply.

No worries. I appreciate the return comments.
 
B

Ben Bacarisse

Tim Rentsch said:
Ben Bacarisse <[email protected]> writes:

Oops, there is a bit of confusion here that I should clear
up. My intention is that the type 'Func' include the pointerness
of pointer-to-function (eg, 'typedef void (*Func)(int)').

Ah. We've been talking about different things. Note you did comment
directly on my example that did not include the pointerness in the
typedef!

When the defined type includes the pointerness then there is only one
correct usage (Func f) but I'd probably include a hint in the type name
(void (*Funcp)(int)). When the type is a function type (void Func(int))
avoiding the automatic parameter type adjustment seems to me clearer --
hence my preference for a * in a parameter declaration in such cases but
that is not, it seems, what you were talking about.

My preference for not including the * in the typedef is partly explained
here:
I rarely define actual function types, since they are almost
never the types the program needs.

In several cases I've found them useful which may explain our different
preferences. In more than once case I've found the ability to declare
external functions via a function type to be handy:

typedef Value Operator(Value *);
extern Operator op_add, op_sub, op_mul, op_div /* ... */;
Operator *op_table[] = {
op_add, op_sub, op_mul, op_div /* ... */
};

The advantage grows if you are using the pre-processor:

extern Operator OP_LIST;
Operator *op_table[] = { OP_LIST };

<snip>
 
T

Tim Rentsch

Ben Bacarisse said:
Ah. We've been talking about different things. Note you did comment
directly on my example that did not include the pointerness in the
typedef!

Yes, it's possible I missed or glossed over this difference,
expecting my comments would be understood from context.
Sorry about that.
When the defined type includes the pointerness then there is only one
correct usage (Func f) but I'd probably include a hint in the type name
(void (*Funcp)(int)).

Right, and reasoning backwards I thought you would realize
that I intended the * to be in the typedef. Silly me. :)
When the type is a function type (void Func(int))
avoiding the automatic parameter type adjustment seems to me clearer --
hence my preference for a * in a parameter declaration in such cases but
that is not, it seems, what you were talking about.

I'm generally in agreement on this, and that's another reason
why I thought you'd understand I intended the * to be in the
typedef. Silly me. :)

My preference for not including the * in the typedef is partly explained
here:
I rarely define actual function types, since they are almost
never the types the program needs.

In several cases I've found them useful which may explain our different
preferences. In more than once case I've found the ability to declare
external functions via a function type to be handy:

typedef Value Operator(Value *);
extern Operator op_add, op_sub, op_mul, op_div /* ... */;
Operator *op_table[] = {
op_add, op_sub, op_mul, op_div /* ... */
};

The advantage grows if you are using the pre-processor:

extern Operator OP_LIST;
Operator *op_table[] = { OP_LIST };

Yes, I understand the motivation provided by this example. It's
not as compelling for me because I almost never write function
declarations by hand; in almost all cases they are generated
automatically from the definitions and mechanically made
available in the appropriate header files. Because of that
normally I would just #include the appropriate header files, and
not write the 'extern Operator ...' lines. Hence there wouldn't
be any need for the non-pointer function type, and there would
be a typedef just for the pointer-ful function type.
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top