开发者

What's the difference between these 2 declarations?

Here's a simple and delicate question. Could someone explain the difference between a and b?

void (*a)(int x, int y)
void (*b(int x, int y))(int)

This question arise from the following Linux function declaration:

void (*signal开发者_StackOverflow社区(int sig, void (*func)(int)))(int);

Solution

The following program makes a good demo.

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

void ouch(int sig)
{
   printf("OUCH! - I got signal %d\n", sig);
   signal(SIGINT, SIG_DFL);
}


void (*g())(int) // just like the b
{
   return ouch;
}

int main()
{

   void (*f)(int); // just like the a
   f=g();
   signal(SIGINT, f);

   while(1)
   {
      printf("Hello, world!\n");
      sleep(1);
   }
}


The designers of C chose to name their types in a way that the use case of the type matches, as closely as possible, the way in which you use that type to get a value. So, for example, when you have a declaration like

int a;

You can just say a to get an int. If you have a type like

int *a;

Then you have to dereference a by writing *a to get an int.

You can use similar, albeit more complex, logic to decode the types you posted. Let's start with

void (*a)(int x, int y)

This says that if you dereference a (by writing *a), then what you're left with is something that looks like

void (int x, int y)

Which is a function taking in two ints and returns void. In other words, you can think of a as a pointer to a function; once dereferenced, you get back the function.

Now for this beast:

void (*b(int x, int y))(int)

This one's trickier. The idea is as follows. If you take b and pass in two arguments into it, then you get back something that looks like this:

void (*)(int)

Which is a pointer to a function taking in an int and returning void. In other words, b is a function that takes two arguments, then returns a function pointer that takes one argument and returns void.

It's somewhat tricky to decode these types, so often you don't seem them written this way and instead use typedef to simplify things. For example, this typedef:

typedef void (*FunctionTakingTwoInts)(int, int);

Says that you can use FunctionTakingTwoInts to define a function pointer that points at a function that takes in two ints and returns void. From here, the declaration of a simplifies down to

FunctionTakingTwoInts a;

Similarly, in the case of b, let's define the type

typedef void (*FunctionTakingOneInt)(int);

Now, we can rewrite b as

FunctionTakingOneInt b(int x, int y);

From which, I think, it's much clearer what the type actually means.

Hope this helps!


Short version: a declares a pointer to a function. b declares a function that returns a pointer to a function.

Longer version: You know the following pattern to declare a pointer to a function

void (*f)(int x, int y)

Now, take the "f", and modify it. For example, make it an array

void (*f[3])(int x, int y)

Now, instead of having a pointer to a function, you have an array of pointer to functions. Now if you instead modify it to be a function rather than an array, you have transformed the first declaration to the second declaration

void (*f(void))(int x, int y)

You have modified it to be a function that returns a pointer to a function. Instead of having no parameter like in this case, your declaration has two parameters. One of which is an int and the other of which is another pointer to function.

It's easier to use typedefs than to combine the C declarators for doing this though.

// your example
typedef void signal_fn(int);
signal_fn *signal(int sig, signal_fn *func);

// my example above
typedef void f_fn(int x, int y);
f_fn *f(void);


Replace (*a) with foo:

void foo(int x, int y);

a is a pointer to a function like that.

Likewise, replace (*b(int x, int y)) with foo:

void foo(int);

b(int x, int y) returns a pointer to a function like that.


http://cdecl.org/ can be a good help for declarations like this. Unfortunately, it doesn't handle named function parameters, so those have to be removed. Feeding in

void (signal(int , void ()(int)))(int)

gives:

declare signal as function (int, pointer to function (int) returning void) returning pointer to function (int) returning void

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜