Skip to content

Pointer to function and function type

典型例子

下面的典型的例子来源自:

1、c-faq The Clockwise/Spiral Rule

Pointer to function

                 +--------------------+
                 | +---+              |
                 | |+-+|              |
                 | |^ ||              |
            char *(*fp)( int, float *);
             ^   ^ ^  ||              |
             |   | +--+|              |
             |   +-----+              |
             +------------------------+

fp就是典型的pointer to function

Function type

                      +-----------------------------+
                      |                  +---+      |
                      |  +---+           |+-+|      |
                      |  ^   |           |^ ||      |
                void (*signal(int, void (*fp)(int)))(int);
                 ^    ^      |      ^    ^  ||      |
                 |    +------+      |    +--+|      |
                 |                  +--------+      |
                 +----------------------------------+

signal就是典型的function type。

对比凸显差异的例子

typedef int* Function(int*); // function pointer
typedef int* (*PointerToFunction)(int*); // pointer to function

void in function type and function pointer

本节收录了一些使用void的例子。

stackoverflow What does C expression ((void(*)(void))0)(); mean?

((void(*)(void))0)();

NOTE:

1、结合了pointer to function 、cast 、function invokation

So we have integer 0 type casting to this tricky type (void(*))(void) and then executing it. Source claims that this should work, but what does it actually?

This must be one of those C jokes like #define TRUE FALSE, I suppose.

A

This is a function expecting no arguments and returning no value:

void f(void)

This is a pointer to a function expecting no arguments and returning no value:

void (*p)(void)

This is the type of that pointer:

void (*)(void) /* just remove the p! */

This is that type in parentheses:

(void (*)(void))

This is a cast to that type (the type in parentheses, followed by a value):

(void (*)(void))0

Still with me? so far we have the integer value 0 cast to a pointer-to-function-that-takes-no-arguments-and-returns-nothing.

The cast is an expression with pointer-to-function type. When you have one of those you can call it like this:

(your expression here)(arguments to the function)

The first set of parentheses are just for precedence, and sometimes might not be needed (but this time they are). The end result:

((void (*)(void))0)(/* no args */);

Takes the value 0, casts it to pointer-to-function-expecting-no-arguments-and-returning-nothing, and calls it, supply no arguments.

A

The syntax to cast address to a function pointer and then call it would look like this:

((void (*)(void))address)();

It might be clearer to do something like this though:

void (*fptr)(void) = (void (*)(void))address;
fptr();

Said that ((void(*)(void))0)(); instruction is used to jump to 0 in firmwares usually. It is a bit improper because it actually calls in 0 instead of jumping to 0, but practically it won't make any difference (a fw hot reboot will be performed)

stackoverflow What is void(*)(void *) [duplicate]

A

It's a function pointer.

void (*destroy)(void *data)

destroy is a pointer to a function which returns void and takes a void* as an argument.

cdecl.org is a useful tool for discerning complex C declarations. Also, take a look at the spiral rule.

void(void)

sizeof operator的例子中看到了这个声明,其中的注释说它声明的是一个function

    printf("sizeof(void(*)(void))  = %zu\n", sizeof(void(*)(void)));
    printf("sizeof(char[10])       = %zu\n", sizeof(char[10]));
//  printf("sizeof(void(void))     = %zu\n", sizeof(void(void))); // Error: function type

它是声明的function type,可以参看Typedef Function Type

iso-9899 Typedef Function Type

There's no need to typedef pointers to function types, typedefing a function type makes things clearer.

'function' is a pointer to a function type:

typedef int (*function)(int a, int b);
function pointer;

The alternative of a non-pointer function type is:

typedef int function(int a, int b);
function *pointer;

Code Sample

#include <stdio.h>

int add(int a, int b) {
    return a + b;
}

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

typedef int function(int a, int b);

int call_function(function *p, int a, int b) {
    return p(a, b);
}

int main(void) {
    int sum;

    sum = call_function(&add, 10, 5);
    printf("add: %d\n", sum);

    sum = call_function(&sub, 10, 5);
    printf("sub: %d\n", sum);

    return 0;
}

Function pointer and type aliasing

Function pointer and type aliasing有时候是比较容易混淆的,下面是一些例子:

csdn 详解virtual table

#include <iostream>
using namespace std;
class Base
{

public:

    virtual void f()
    {
        cout << "Base::f" << endl;
    }

    virtual void g()
    {
        cout << "Base::g" << endl;
    }

    virtual void h()
    {
        cout << "Base::h" << endl;
    }

};
int main()
{
    typedef void (*Fun)(void);

    Base b;

    Fun pFun = NULL;

    cout << "虚函数表地址:" << (int*) (&b) << endl;

    cout << "虚函数表的第一个函数地址:" << (int*) *(int*) (&b) << endl;

    // Invoke the first virtual function

    pFun = (Fun) *((int*) *(int*) (&b));

    pFun();
}
// g++ test.cpp -Wall -pendatic

1、上述例子就是混合了pointer to function、type aliasing的,如果熟练掌握,非常可能会理解错误

2、第一次看到: (int*) *(int*) (&b) 时,我以为 (int*) *(int*) 是pointer to function passing pointer to int and return pointer to int,这是错误的,,正确的pointer to function的写法如下:

int* (*PointerToFunction)(int*) 

它的准确含义是:

a、(int*) (&b) 转换为 int* 类型

b、读取值: *(int*) (&b)

c、(int*) *(int*) (&b) 将读取的值,再转换为 int* 类型