I don't understand typedef example

A

André Hänsel

Hi list,

"The C book", Chapter 8.3 states:

-----
As a word of warning, typedef can only be used to declare the type of
return value from a function, not the overall type of the function.
The overall type includes information about the function's parameters
as well as the type of its return value.

/*
* Using typedef, declare 'func' to have type
* 'function taking two int arguments, returning int'
*/
typedef int func(int, int);

/* ERROR */
func func_name{ /*....*/ }

/* Correct. Returns pointer to a type 'func' */
func *func_name(){ /*....*/ }
-----

This does not make any sense to me. He says that it is not possible to
typedef the function parameters' types and in the next line (the
comment) he says that he declares "func" to be "function taking two
int arguments" using typedef.

Can you explain this to me?

Regards,
André
 
K

Keith Thompson

André Hänsel said:
Hi list,

"The C book", Chapter 8.3 states:

-----
As a word of warning, typedef can only be used to declare the type of
return value from a function, not the overall type of the function.
The overall type includes information about the function's parameters
as well as the type of its return value.

/*
* Using typedef, declare 'func' to have type
* 'function taking two int arguments, returning int'
*/
typedef int func(int, int);

/* ERROR */
func func_name{ /*....*/ }

/* Correct. Returns pointer to a type 'func' */
func *func_name(){ /*....*/ }
-----

This does not make any sense to me. He says that it is not possible to
typedef the function parameters' types and in the next line (the
comment) he says that he declares "func" to be "function taking two
int arguments" using typedef.

You can declare a typedef for a function type, but you can't use such
a typedef to define a function of that type.

But given that func is a typedef for a function type, func* is a
pointer-to-function type. In his "Correct." example, he doesn't
declare func_name as a function of type func; he declares it as a
function that returns a func*.
 
F

Fred

Hi list,

"The C book", Chapter 8.3 states:

-----
As a word of warning, typedef can only be used to declare the type of
return value from a function, not the overall type of the function.
The overall type includes information about the function's parameters
as well as the type of its return value.

/*
* Using typedef, declare 'func' to have type
* 'function taking two int arguments, returning int'
*/
typedef int func(int, int);

/* ERROR */
func func_name{ /*....*/ }

/* Correct. Returns pointer to a type 'func' */
func *func_name(){ /*....*/ }
-----

This does not make any sense to me. He says that it is not possible to
typedef the function parameters' types and in the next line (the
comment) he says that he declares "func" to be "function taking two
int arguments" using typedef.

Can you explain this to me?

Consider this:
typedef char * String;

Then:

String myfunc(...);

So myfunc is a function that returns a string (i.e., a char *).

So your func is typedef'd to be a function taking two int
arguments and returning an int.

Then you declare
func func_name(...);

Your intent was probably to try to show that func_name is
a function taking two int arguments and returning an int.

But in reality you have said that func_name is a function
that returns a func - that is, a function that returns
a function that takes two int args and returns an int.

One common use of such a typedef is when passing a
function as an argument. For example,

int func_name( int a, int b ) {...};

int mynewfunc( int x, int y, func proc ) {
/* somewhere this probably has something like this
* to invoke the function passed in:
*/
int n =(*proc)( a, b );

return n;
}

Then you can call mynewfunc:

int d = mynewfunc( 2, 5, func_name );
 
S

Stephen Sprunk

André Hänsel said:
"The C book", Chapter 8.3 states:

-----
As a word of warning, typedef can only be used to declare the type of
return value from a function, not the overall type of the function.
The overall type includes information about the function's parameters
as well as the type of its return value.

/*
* Using typedef, declare 'func' to have type
* 'function taking two int arguments, returning int'
*/
typedef int func(int, int);

/* ERROR */
func func_name{ /*....*/ }

/* Correct. Returns pointer to a type 'func' */
func *func_name(){ /*....*/ }
-----

This does not make any sense to me. He says that it is not possible to
typedef the function parameters' types and in the next line (the
comment) he says that he declares "func" to be "function taking two
int arguments" using typedef.

Can you explain this to me?


"func" means a function taking two ints and returning an int. If you write:

func *func_name() { /*....*/ }

what you have is a function taking no arguments and returning a
pointer-to-func.

This:

func func_name { /*....*/ }

is not valid, period, because (a) func_name doesn't have an argument
list, and (b) func_name can't return a function, only a pointer-to-function.

It never occurred to me to try to use a function typedef to declare the
return value and arguments to another function; that's just not the way
the C syntax works. You could hack up something similar using #define
if you really wanted to, but why?

S
 
K

Keith Thompson

Fred said:
Consider this:
typedef char * String;

Then:

String myfunc(...);

So myfunc is a function that returns a string (i.e., a char *).

That particular typedef is a bad idea, just because of the name.
A char* is not a string. A char* value can point to (the first
character of) a string. A "string" is defined as "a contiguous
sequence of characters terminated by and including the first null
character"; it is *not* a pointer. Suggested reading: sections 6
and 8 of the comp.lang.c FAQ, <http://www.c-faq.com>.

But apart from the terminology, yes, myfunc returns a char*.
So your func is typedef'd to be a function taking two int
arguments and returning an int.

Right.

Functions, like objects, have types. If I define a function:

int foo(int n) { return n; }

then the function foo has a type that can be described as "function
taking an int argument and returning an int result". This type
can be written in C as "int (int)" (the type name is obtained by
taking the declaration and dropping the function's name). It's
important to keep in mind that a function and a function type
are two different things, just as an object (variable) and its
type are two different things.

The purpose of a typedef is to create a new name, an alias, for an
existing type. You can do this for a function type as easily as for
any other type. (Well, almost as easily; the syntax can be a bit
daunting.)

So the declaration:

typedef int func(int, int);

declare "func" as a name (an alias) for the type "function taking
two int arguments returning an int result", or "int(int, int)".

Once you've declared this alias, you can use it almost anywhere you
can use the original type. For example:
func *ptr;
declared ptr as a pointer object that can points to a function of the
appropriate type, and
func *array_of_pointers[42];
declares array_of_pointers as an array of such pointers.
Then you declare
func func_name(...);

Your intent was probably to try to show that func_name is
a function taking two int arguments and returning an int.

But in reality you have said that func_name is a function
that returns a func - that is, a function that returns
a function that takes two int args and returns an int.

Which is illegal. You can't legally have a function that returns a
function. You *can* have a function that returns a function pointer.
One common use of such a typedef is when passing a
function as an argument. For example,

int func_name( int a, int b ) {...};

int mynewfunc( int x, int y, func proc ) {

Again, this is illegal, since you can't have a parameter of function
type. You can have a parameter of pointer-to-function type, so this
would be legal (and is probably what you meant):

int mynewfunc( int x, int y, func *proc ) {
/* somewhere this probably has something like this
* to invoke the function passed in:
*/
int n =(*proc)( a, b );

return n;
}

Then you can call mynewfunc:

int d = mynewfunc( 2, 5, func_name );

func_name is a function, so yes, given that mynewfunc takes an
argument of type func*, this call is valid. Any expression of
function type, including a function name, is implicitly converted to a
pointer to the function.

Given that func is a typedef for a function type, you declare
a function of that type:

func foo;

But you can't use it to *define* the same function:

func foo { return 42 }; /* ILLEGAL */

In my opinion, it's clearer *not* to use the typedef in the function
declaration. (It's perfectly ok to use a typedef as *part of* a
function declaration, such as "func *bar(void)".) I prefer to keep a
function's declaration and definition as similar as possible, so I'd
write:

/* declaration: */
int foo(int a, int b);

/* definition: */
int foo(int a, int b) { /* ... */ }

Finally, you can declare a typedef either for the function type itself
or for a pointer to the function type:

typedef int func(int, int);

typedef int *func_ptr(int, int);

There are arguments for both forms. In code that I've seen, the
latter form is more common than the former; I think a lot of C
programmers aren't even aware that you can declare a typedef for
a function type. On the other hand, declaring a typedef for a
pointer type is generally a bad idea; the fact that something is a
pointer is an important part of the information you need to use it,
and hiding that information behind an alias can cause confusion.
On the other other hand, this argument isn't as strong for
pointers to functions as it is for pointers to objects. You should
be familiar with both forms.
 
B

Ben Bacarisse

Stephen Sprunk said:
André Hänsel wrote:
This:

func func_name { /*....*/ }

is not valid, period, because (a) func_name doesn't have an argument
list, and (b) func_name can't return a function, only a
pointer-to-function.

It is often more trouble than it is worth to say why something is
invalid (since it is wrong, it could mean anything at all) but I think
you go to far with (b). If I had just read about C's type system and
knew nothing else, I would take

func func_name { /*....*/ }

to be a definition of func_name as a function that returns an int.
After all,

func func_name;

declares it as such, so why would C not permit a definition by adding
a block? Yes, your (a) is the key problem -- there is no obvious
argument list, but the implied type is fine.
 
F

Fred

Consider this:
typedef char * String;

String myfunc(...);
So myfunc is a function that returns a string (i.e., a char *).

That particular typedef is a bad idea, just because of the name.
A char* is not a string.  A char* value can point to (the first
character of) a string.  A "string" is defined as "a contiguous
sequence of characters terminated by and including the first null
character"; it is *not* a pointer.  Suggested reading: sections 6
and 8 of the comp.lang.c FAQ, <http://www.c-faq.com>.

But apart from the terminology, yes, myfunc returns a char*.
So your func is typedef'd to be a function taking two int
arguments and returning an int.

Right.

Functions, like objects, have types.  If I define a function:

    int foo(int n) { return n; }

then the function foo has a type that can be described as "function
taking an int argument and returning an int result".  This type
can be written in C as "int (int)" (the type name is obtained by
taking the declaration and dropping the function's name).  It's
important to keep in mind that a function and a function type
are two different things, just as an object (variable) and its
type are two different things.

The purpose of a typedef is to create a new name, an alias, for an
existing type.  You can do this for a function type as easily as for
any other type.  (Well, almost as easily; the syntax can be a bit
daunting.)

So the declaration:

    typedef int func(int, int);

declare "func" as a name (an alias) for the type "function taking
two int arguments returning an int result", or "int(int, int)".

Once you've declared this alias, you can use it almost anywhere you
can use the original type.  For example:
    func *ptr;
declared ptr as a pointer object that can points to a function of the
appropriate type, and
    func *array_of_pointers[42];
declares array_of_pointers as an array of such pointers.
Then you declare
func func_name(...);
Your intent was probably to try to show that func_name is
a function taking two int arguments and returning an int.
But in reality you have said that func_name is a function
that returns a func - that is, a function that returns
a function that takes two int args and returns an int.

Which is illegal.  You can't legally have a function that returns a
function.  You *can* have a function that returns a function pointer.
One common use of such a typedef is when passing a
function as an argument. For example,
int func_name( int a, int b ) {...};
int mynewfunc( int x, int y, func proc ) {

Again, this is illegal, since you can't have a parameter of function
type.  You can have a parameter of pointer-to-function type, so this
would be legal (and is probably what you meant):

    int mynewfunc( int x, int y, func *proc ) {
/* somewhere this probably has something like this
 * to invoke the function passed in:
 */
   int n =(*proc)( a, b );
   return n;
}
Then you can call mynewfunc:
 int d = mynewfunc( 2, 5, func_name );

func_name is a function, so yes, given that mynewfunc takes an
argument of type func*, this call is valid.  Any expression of
function type, including a function name, is implicitly converted to a
pointer to the function.

Given that func is a typedef for a function type, you declare
a function of that type:

    func foo;

But you can't use it to *define* the same function:

    func foo { return 42 }; /* ILLEGAL */

In my opinion, it's clearer *not* to use the typedef in the function
declaration.  (It's perfectly ok to use a typedef as *part of* a
function declaration, such as "func *bar(void)".)  I prefer to keep a
function's declaration and definition as similar as possible, so I'd
write:

    /* declaration: */
    int foo(int a, int b);

    /* definition: */
    int foo(int a, int b) { /* ... */ }

Finally, you can declare a typedef either for the function type itself
or for a pointer to the function type:

    typedef int func(int, int);

    typedef int *func_ptr(int, int);

There are arguments for both forms.  In code that I've seen, the
latter form is more common than the former; I think a lot of C
programmers aren't even aware that you can declare a typedef for
a function type.  On the other hand, declaring a typedef for a
pointer type is generally a bad idea; the fact that something is a
pointer is an important part of the information you need to use it,
and hiding that information behind an alias can cause confusion.
On the other other hand, this argument isn't as strong for
pointers to functions as it is for pointers to objects.  You should
be familiar with both forms.

--
Keith Thompson (The_Other_Keith) (e-mail address removed)  <http://www.ghoti.net/~kst>
Nokia
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"- Hide quoted text -

- Show quoted text -

Oops - I misread the original typedef - thought it was
typdef int (*func)(int, int);
 
O

Old Wolf

It is often more trouble than it is worth to say why something is
invalid (since it is wrong, it could mean anything at all) but I think
you go to far with (b).  If I had just read about C's type system and
knew nothing else, I would take

 func func_name { /*....*/ }

to be a definition of func_name as a function that returns an int.

What are the names of the parameters? It
would be annoying as a programmer to have
to refer back to the definition of 'func',
to find out how to use a parameter, not to
mention maintenance problems if someone
mucks with the typedef.

I agree that it would be useful to have
some sort of syntax for defining a function
to match an existing typedef, but I can't
really think of any such good syntax to do this.
 
O

Old Wolf

Hi list,

"The C book", Chapter 8.3 states:

-----
As a word of warning, typedef can only be used to declare the type of
return value from a function, not the overall type of the function.
The overall type includes information about the function's parameters
as well as the type of its return value.

This paragraph is completely wrong. A
function typedef can include the function's
formal parameter list. In fact the example
you give does exactly that. The following
code is wrong:

typedef int func(int, int);

func f;

int f(void) { return 0; }
 
B

Ben Bacarisse

Old Wolf said:
What are the names of the parameters?

Yes, that is the main problem. I agreed with that part of the post.
It
would be annoying as a programmer to have
to refer back to the definition of 'func',
to find out how to use a parameter, not to
mention maintenance problems if someone
mucks with the typedef.

Yes. The typedef may have no named parameters, or there may be more
than one typedef with different names (depending on #if for example)
so it would be a nightmare.
I agree that it would be useful to have
some sort of syntax for defining a function
to match an existing typedef, but I can't
really think of any such good syntax to do this.

One could do:

typedef int functype(int, int);

(functype f)(a, b)
{
return a + b;
}

You could be permitted to repeat the types if you like:

int (functype f)(int a, int b) { ... }

and the compiler would check that they match.

The parentheses group the function types with name and though odd, not
so very odd since C uses ()s for grouping in types already.
 
A

André Hänsel

Thanks for all your answers. They make it clear. So I understand that
all the author wanted to say is that there is no syntax in C to use a
typedef'd function type to define (or even declare) a function of that
type.

Since the only use of such a typedef is to make a type "pointer to
such a function" I probably will stick to the "typedef int
*pointer_to_such_function(int,int)" syntax in my own code.
 
A

André Hänsel

Did you understand the part of the answers
which explained about the author being wrong?

You *can* use a typedef to declare a function.

Actually I don't think the author is wrong but he expresses the facts
in a very unfortunate way. I think by the sentence "As a word of
warning, typedef can only be used to declare the type of return value
from a function, not the overall type of the function." he means
something like "The typedef'd 'type name' cannot be used to define a
function of this type, it can only be used to define a function
returning a pointer to a funtion of this type."
This is what you meant by "using a typedef to declare a function",
isn't it? Or is there really a way to define a function of this very
type?
 
B

Barry Schwarz

Thanks for all your answers. They make it clear. So I understand that
all the author wanted to say is that there is no syntax in C to use a
typedef'd function type to define (or even declare) a function of that
type.

Since the only use of such a typedef is to make a type "pointer to
such a function" I probably will stick to the "typedef int
*pointer_to_such_function(int,int)" syntax in my own code.

You probably meant
typedef int (*ptr)(int, int);
otherwise the asterisk binds to the int.
 
L

luser-ex-troll

Yes, that is the main problem.  I agreed with that part of the post.


Yes.  The typedef may have no named parameters, or there may be more
than one typedef with different names (depending on #if for example)
so it would be a nightmare.


One could do:

  typedef int functype(int, int);

  (functype f)(a, b)
  {
      return a + b;
  }

You could be permitted to repeat the types if you like:

  int (functype f)(int a, int b) { ... }

and the compiler would check that they match.

The parentheses group the function types with name and though odd, not
so very odd since C uses ()s for grouping in types already.

I saw that and got so excited that I copied it straight into an editor
and tried to compile. It doesn't work. But I came up with a use that
does work, declaring a function with a function-pointer arg which is
declared by example.

int b(int a, int b) {
return a - b;
}

typedef typeof(b) functype;

int gen_interface(int foo, functype *fp);
 
K

Keith Thompson

André Hänsel said:
Actually I don't think the author is wrong but he expresses the facts
in a very unfortunate way. I think by the sentence "As a word of
warning, typedef can only be used to declare the type of return value
from a function, not the overall type of the function." he means
something like "The typedef'd 'type name' cannot be used to define a
function of this type, it can only be used to define a function
returning a pointer to a funtion of this type."
This is what you meant by "using a typedef to declare a function",
isn't it? Or is there really a way to define a function of this very
type?

The terms "declare" and "define" are not interchangeable. You can use
a typedef to *declare* a function, where the typedef specifies the
type of the function itself. You cannot similarly use a typedef to
*define* a function. (Of course a typedef can be used in the
function's return type or parameter types; it just can't be used for
the type of the function itself.)

For example, this is legal:

#include <stdio.h>

/* func_type is a function type, not a pointer-to-function type */
typedef void func_type(void);

/* A function declaration, not a definition: */
func_type say_hello;

int main(void) {
say_hello();
return 0;
}

/* A function definition: */
void say_hello(void) {
puts("Hello");
}

The function say_hello is of type func_type, but you cannot legally
rewrite the *definition* of say_hello using the type name "func_type".

And as a matter of style, I prefer not to use typedefs for function
declarations either, since I like to keep declarations and definitions
as similar as possible (apart from the lack of a body on the
declaration, of course).

(In the above, I largely ignored the fact that a definition is also a
declaration.)
 
K

Keith Thompson

luser-ex-troll said:
I saw that and got so excited that I copied it straight into an editor
and tried to compile. It doesn't work. But I came up with a use that
does work, declaring a function with a function-pointer arg which is
declared by example.

int b(int a, int b) {
return a - b;
}

typedef typeof(b) functype;

int gen_interface(int foo, functype *fp);

typeof is non-standard; I think it's a gcc extension.
 
B

Ben Bacarisse

luser-ex-troll said:
On Mar 18, 10:52 pm, Ben Bacarisse <[email protected]> wrote:

I saw that and got so excited that I copied it straight into an editor
and tried to compile. It doesn't work.

Yes, I hope it is clear I was talking about what one might do in a
hypothetical language like C...
But I came up with a use that
does work, declaring a function with a function-pointer arg which is
declared by example.

int b(int a, int b) {
return a - b;
}

typedef typeof(b) functype;

int gen_interface(int foo, functype *fp);

typeof is (as has been pointed out already) non-standard but if you
think about it, all C typedefs are declared "by example" -- you write
an example declaration:

int b(int a, int b);

and simply replace the name with the name you want for the alias abd
put typedef in front:

typdef int functype(int a, int b);

and now functype works like your typeof example. This is true of all
tyepdefs -- they are example declarations with an extra keyword in
front.
 
A

André Hänsel

Actually I don't think the author is wrong but he expresses the facts
in a very unfortunate way. I think by the sentence "As a word of
warning, typedef can only be used to declare the type of return value
from a function, not the overall type of the function." he means
something like "The typedef'd 'type name' cannot be used to define a
function of this type, it can only be used to define a function
returning a pointer to a funtion of this type."
This is what you meant by "using a typedef to declare a function",
isn't it?
No.

Or is there really a way to define a function of this very type?

No.
A typedef can be used to declare a function type.
A typedef can't be used to define a function.
I just posted this code recently:

/* BEGIN new.c */

#include <stdio.h>

#define STRING1 "\n/* BEGIN output new.c */\n"
#define STRING2 "/* END output new.c */"

typedef void *copyfunc(void *s1, const void *s2, size_t n);
/*
** mem_cpy and mem_move
** are functions declared with a copyfunc typedef.
*/
copyfunc mem_cpy;
copyfunc mem_move;

int main(void)
{
     char string1[sizeof STRING1];
     char string2[sizeof STRING2];

     mem_cpy(string1, STRING1, sizeof string1);
     mem_move(string2, STRING2, sizeof string2);
     puts(string1);
     puts(string2);
     return 0;

}

void *mem_cpy(void *s1, const void *s2, size_t n)
{
           unsigned char *p1 = s1;
     const unsigned char *p2 = s2;

     while (n-- != 0) {
         *p1++ = *p2++;
     }
     return s1;

}

void *mem_move(void *s1, const void *s2, size_t n)
{
           unsigned char *p1 = s1;
     const unsigned char *p2 = s2;

     p2 += n;
     while (p2 != s2 && --p2 != s1) {
         ;
     }
     if (p2 != s2) {
         p2  = s2;
         while (n-- != 0) {
             p1[n] = p2[n];
         }
     } else {
         while (n-- != 0) {
             *p1++ = *p2++;
         }
     }
     return s1;

}

/* END new.c */

Oh, now I understand. Of course I was aware of the difference between
the declaration and the definition, I simply could not understand why
a language may provide a syntax to declare a function using the
typedef but *not* provide a syntax to *define* the function using it.
 
A

André Hänsel

You probably meant
   typedef int (*ptr)(int, int);
otherwise the asterisk binds to the int.

I think I did, yes.

I copied it from Keith's post:
Finally, you can declare a typedef either for the function type itself
or for a pointer to the function type:

typedef int func(int, int);

typedef int *func_ptr(int, int);

There are arguments for both forms. In code that I've seen, the
latter form is more common than the former;

So I think the parentheses slipped his fingers, too. Or did he mean
something completely different?
 
K

Keith Thompson

André Hänsel said:
I think I did, yes.

I copied it from Keith's post:


So I think the parentheses slipped his fingers, too. Or did he mean
something completely different?

No, I just goofed.
 

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,744
Messages
2,569,483
Members
44,902
Latest member
Elena68X5

Latest Threads

Top