-1

I am working with an intentionally obfuscated code that contains a weird typedef that I am not able to comprehend. Could anyone explain what the following typedef means:

typedef void (*p_t)(char* a1, char* a2, int a3);

Later in the main its being used as follows:

int main(void) {
    p_t p = &some_function;
    p("foo", "bar", 42);
}
Stargateur
  • 24,473
  • 8
  • 65
  • 91
sophist_pt
  • 329
  • 1
  • 8
  • 19

3 Answers3

9

typedef void (*p_t)(char* a1, char* a2, int a3); is a typedef of a pointer to a function that accepts arguments char* a1, char* a2, int a3 and returns a void (no return).


Think of a function declaration (without any typedef involved), for example:

void fn(char* a1, char* a2, int a3);

Now, suppose that you want some pointer p to point to this function, then an assignment like p = fn should make sense. But what would the type of that p be? It would be a pointer to a function, but since functions have different signatures (making the "type" of the function different), you need to also specify the signature of the function that it points to. In your case, you need a pointer to a function that accepts three arguments: 1.) a pointer to a char, 2.) another pointer to a char, and 3.) an int. Also, the function returns a void. All this needs to be specified in the type of p. So your p might be declared (and subsequently assigned) as

void (*p)(char* a1, char* a2, int a3);
p = fn;

The part that may look weird is the * (declaring p as a pointer to something), which needs to go in parentheses with the p identifier. Seeing some construct like (*p)(...) should be a quick hint to ask yourself if you're looking at a pointer to a function. If you're going to use such a pointer to a function over and over, rather than have to type all that out again and again (and risk inconsistencies should you decide to change the function signature), it is convenient to make a typedef. In your case, this is

typedef void (*p_t)(char* a1, char* a2, int a3);

See the "Clockwise/Spiral Rule".


In your example, you have

p_t p = &some_function;

This is declaring a variable p of type p_t. As mentioned above, this is a pointer to a function that accepts three arguments and returns a void. This line also initializes p with the value &some_function. Apparently some_function is the identifier of a function that is defined somewhere and accepts these three arguments and returns a void. It initializes p to point to this function, so that on the next line calls it:

p("foo", "bar", 42);

I'm surprised this isn't written as

(*p)("foo", "bar", 42);

This dereferences p, which gives the function some_function, then calls that function with the arguments "foo", "bar", and 42. This is convenient because you could (if you wanted) make p point to some other function (with the same signature). The associated function can therefore be dynamic.


It is worth mentioning that the & in p_t p = &some_function; is not necessary. It doesn't hurt anything, but it's not needed. Another strange thing about pointers to functions is that you can reference and dereference as many times as you want, and they mean the same thing! (See Why do function pointer definitions work with any number of ampersands '&' or asterisks '*'?)

e0k
  • 6,961
  • 2
  • 23
  • 30
2

It's a typedef for a function pointer.

typedef void (*p_t)(char* a1, char* a2, int a3);
        ^      ^    ^
        |      |    |
      return   |    +-----+
      type     |          |
            typedef    argument list
             name

In this case, it's a typedef named p_t. The function returns void and it's arguments are char *, char *, int.

Stephen Newell
  • 7,330
  • 1
  • 24
  • 28
1

This is explained in "The C Programming Language" by Brian Kernighan and Dennis Ritchie.

For example int *i is a pointer to int because it says that expression *i should evaluate to type int. More examples of this:

  • int (*func)() is a pointer to function returning int because expression (*func)() evaluates to type int.
  • int *p[8] is an array of pointers to int because expression *p[x] evaluates to type int.
  • int (*p)[8] is a pointer to array of 8 int's (int[8]) because expression (*p)[x] evaluates to type int.
  • int (*(*p[8])())() is an array of 8 pointers to functions returning pointers to a function returning int because expression (*(*p[x])())() evaluates to type int.

Therefor lets look at typedef void (*p_t)(char* a1, char* a2, int a3):

  • (*p_t) expression of type p_t might be dereferenced and called (pointer to function).
  • It should be passed arguments of types char *, char * and int.
  • The resulting type of that expression is void.

It is a pointer to function taking char *, char *, int which has no return value.