0

I work on my tutorial in C language.

I have a small pice of code that I need to deciph.

Here is the code:

int  f(){return 1;}
int  g(){return 2;}
int (*h(int (*pf1)(), int (*pf2)()))(){
  return (int (*) ())((pf1() > pf2())*(int)pf1 + (pf2()>pf1())*(int)pf2);
}
void main(){
    int res = h(f,g)();
}

I have problem to unndestand this syntex:

int (*h(int (*pf1)(), int (*pf2)()))()

I can't understand what is the meaning of this outter parentheses ->(*h(int (*pf1)(), int (*pf2)()))

and this parentheses() at the end of the function's signature.

Also what is '*h' inside parentheses? I understand that it get two functions and trigger it.

Can I get brif explanation on questions above?

Michael
  • 13,950
  • 57
  • 145
  • 288
  • 1
    That is terrible code, and it's assuming `int` is the same size as a function pointer. – user2357112 Jun 20 '18 at 21:20
  • 1
    The h function returns function pointer, the extra () are because of that. It also crashes at ideone... And no wonder, the return value doesn't look like an address of function to me (but that is rather obfuscated code so...). – hyde Jun 20 '18 at 21:31
  • 1
    On my computer and on... uh, I dunno... about one billion perhaps? at any rate, on many other computers on this planet, the meaning of this program is "Segmentation fault". – n. m. could be an AI Jun 20 '18 at 21:31
  • It actually works on (almost all) 32 bit systems as is, I think. To make it work on (almost) any system, use intptr_t instead of int. Not 100% sure if there even is undefind behavior here then... Quite nice obfuscated code, I hope someone takes time to write an actual answer. This also demonstrates how C is a loaded gun, firmly strapped on your leg pointing at your foot. – hyde Jun 20 '18 at 21:39
  • 1
    Possible duplicate of [How do I understand complicated function declarations?](https://stackoverflow.com/questions/1448849/how-do-i-understand-complicated-function-declarations) – nachiketkulk Jun 20 '18 at 21:49
  • When pf1() and pf2() are equal, it returns null. – Millie Smith Jun 20 '18 at 21:55
  • @hyde your assuming that code like this is normal and necessary; yes guns are dangerous more so when you use them recklessly. – esoterik Jun 20 '18 at 22:13
  • @esoterik No I am not assuming that, you misread my meaning. Code like this should be burned with real fire from any "real" project, and perpetrator flogged. But writing or deciphering it for understanding can be fun. – hyde Jun 21 '18 at 04:33

2 Answers2

4

Function pointers can be tricky to read. I start by reading the inner-most parenthesis, and work my way to the outer-most parenthesis.

Here's a breakdown of that declaration:

int (*h(int (*pf1)(), int (*pf2)()))()

(*pf1)() and (*pf2)() are pointers to functions that accept no parameters (i.e. ()), and both of them return an int.

*h(int (*pf1)() , int (*pf2)()) is a function that accepts two function pointers that returnint s. So, h returns a pointer to a function that accepts nothing and returns an int

Here is a link to some examples of the syntax, and a more elaborate breakdown: https://www.cprogramming.com/tutorial/function-pointers.html


Added:

Since the original code that was provided segfaults, I wrote two different implementations that compare two integers and return the bigger one.

First, look at j. It's just a regular function that accepts two parameters that happen to be function pointers. Those function pointers are then used within the function. And because we said j returns an int, we return the actual integer by calling pf1() or pf2() with ().

Now look at h. In this scenario, h is going to return a pointer *. So we still call the function pointers pf1() and pf2() in h, but when we return, we DO NOT use () because we want to return the whole function pointer (either pf1 or pf2).

Lastly, look at main and see the difference between how j and h are used. Again, j is just a regular function. However, h uses the this syntax: h(f,g)() because h returns a pointer to a function which we then want to call using () to get the actual integer result for printing.

Hope this helps provide a little more clarity with a working example! Good luck!

#include <stdio.h>

int  f(){return 1;}
int  g(){return 2;}

int j(int (*pf1)(), int (*pf2)())
{
    return ((pf1() > pf2() ? pf1() : pf2()));
}

int (*    h( int(*pf1)() , int(*pf2)() )   ) () 
{
    return (pf1() > pf2() ? pf1 : pf2);
}


int main()
{
    int res1 = j(f,g);

    int res2 = h(f,g)();

    //print values returned by calling f and g.
    printf("f: %d \ng: %d\n", f(),g());

    //print result of calling j(f,g)
    printf("res1: %d\n", res1);

    //print result of calling h(f,g)()
    printf("res2: %d\n", res2);

    return 0;
}
Jagawag
  • 76
  • 4
  • 1
    `h` is not a pointer to a function, its a function that returns a pointer to a function... – Chris Dodd Jun 20 '18 at 21:59
  • Thanks for post it really helped me. But there is one thing that I cant understand is why 'h' returns pointer to a function?Isn't it a pointer to the function? – Michael Jun 21 '18 at 15:24
  • 1
    Hi @Michael, I added to the answer to provide clarification, and a working example you can play with. `h` is a function, and it is defined to return a pointer b/c it has `*` in front of the `h`. The pointer that `h` returns must also be a pointer to a void function because we have empty parentheses`( )` at the end of the function signature. – Jagawag Jun 21 '18 at 17:35
2

main calls the function returned by h and returns that result. h compares the output of f and g and returns the function which returns the larger value (else it returns 0). Since the output of g is greater than f, h returns g. Hence main returns 2.

stark
  • 12,615
  • 3
  • 33
  • 50