Is it possible to swap C functions?

2019-02-14 19:56发布

Looking to see if anyone knows if its possible to swap C functions...?

 void swap2(int(*a)(int), int(*b)(int)) {
   int(*temp)(int) = a;
   *a = *b;
   *b = temp;
   // Gives 'Non-object type 'int (int)' is not assignable
 }

 swap2(&funcA, &funcB);

EDIT

More data here as to intention -- Some answers have been provided below which do work such as creating the function ptr using typedef, pointing them to the functions and switching those, which lets you invoke the new swapped ptrs successfully.

BUT calling the functions by their original names after swapping shows no change. Essentially I'm looking for a c equivalent of the objc "swizzle".

I'm beginning to think this isn't possible, due to c's complete lack of reflection, and would require actually modifying the binary itself (obviously not feasible). D:

Comments welcome.

5条回答
倾城 Initia
2楼-- · 2019-02-14 20:29

I'm pretty sure you need pointers to function pointers to swap pointers, no? This type of swapping function swaps values; you really want to deal in addresses. The example function call wouldn't really work because C doesn't treat functions as first-class variables so you can't actually swap functions directly; you need to use pointers to function addresses, since addresses CAN be swapped:

void swap2(int(**a)(int), int(**b)(int)) {
   int(*temp)(int) = *a;
   *a = *b;
   *b = *temp;
}

int(*func1)(int) = &foo;
int(*func2)(int) = &bar;

swap2(&func1, &func2);
查看更多
Bombasti
3楼-- · 2019-02-14 20:29

Your code will give error like "invalid lvalue" at the time of assignment. As I can see in your code you are trying to swap pointers without changing its values so have a look on below solution.

void swap2(int(**a)(int), int(**b)(int)) {   
   int(*temp)(int) = *a;
   *a = *b;
   *b = temp;
}

int main(){
    int(*temp1)(int) = &funcA;
    int(*temp2)(int) = &funcB;
    swap2(&temp1,&temp2);
}
查看更多
老娘就宠你
4楼-- · 2019-02-14 20:33

Yes,you can. Think that a function-pointer is just a memory-address,the single requeriment is: where you will keep such address needs to be mutable. Say,int (*foo)() not really to where foo points to. May be to printf() or fopen().

查看更多
相关推荐>>
5楼-- · 2019-02-14 20:33

Although the subject asks about swapping functions, you actually want to emulate what swizzle does. This just means you want to be able to call the same function name but have it do something different.

A pointer only solution will not give you that behavior. If that is not important to you, then you should adopt one of the function pointer only solutions provided. If it is important to you, then, you will need to introduce a layer of abstraction. The abstraction could use function pointers under the hood (although there are other solutions).

The API to users of this interface would be:

/* API to initialize */
void abstract_func_init ();

/* API to manipulate abstract functions */
typedef int abstract_func_type ();
abstract_func_type * abstract_func_get (abstract_func_type *key);
int abstract_func_set (abstract_func_type *key, abstract_func_type *behavior);

/* the abstract functions */
extern int foo ();
extern int bar ();

The implementation of such an interface could look like:

static void insert (abstract_func_type *key, abstract_func_type **behavior)
{ /* associate key to behavior */ }
static abstract_func_type ** lookup (abstract_func_type *key)
{ /* return behavior from key */ }

abstract_func_type * abstract_func_get (abstract_func_type *k) {
    abstract_func_type **f = lookup(k);
    if (f) return *f;
    return 0;
}

int abstract_func_set (abstract_func_type *k, abstract_func_type *p) {
    abstract_func_type **f = lookup(k);
    if (f) {
        *f = p;
        return 0;
    }
    return -ENOENT;
}

#define DEFINE_ABSTRACT_FUNC(func) \
    static int static_##func (); \
    static abstract_func_type *func##_ptr = static_##func; \
    int func () { return func##_ptr(); } \
    static int static_##func ()

DEFINE_ABSTRACT_FUNC(foo) { return puts("foo"); }
DEFINE_ABSTRACT_FUNC(bar) { return puts("bar"); }

void abstract_func_init () {
    insert(foo, &foo_ptr);
    insert(bar, &bar_ptr);
}

Then, the swap() you initially presented in your post could be implemented like this:

void swap (abstract_func_type *a, abstract_func_type *b) {
    abstract_func_type *ap = abstract_func_get(a);
    abstract_func_type *bp = abstract_func_get(b);
    abstract_func_set(a, bp);
    abstract_func_set(b, ap);
}

Here is a program that calls swap():

    puts("before swap");
    foo();
    bar();
    swap(foo, bar);
    puts("after swap");
    foo();
    bar();

And its output would be:

before swap
foo
bar
after swap
bar
foo

To automate the adding of abstract functions into the lookup table, you could introduce into the build system an extra step that called a script that would grep out the DEFINE_ABSTRACT_FUNC lines, and generate a new source file that had a function with the calls to insert() for each such line.

A complete version of the mock-up can be found here.

查看更多
Root(大扎)
6楼-- · 2019-02-14 20:34

If you use the function pointers like below, it is yes

typedef int (*func_pt)(int);

func_pt a, b;

void swap(func_pt * a, func_pt * b)
{
    func_pt tmp = *b;
    *b = *a;
    *a = tmp;
}

swap(&a, &b);

Or you use it as this, I think it is no:

int test1(int a)
{
    return a;
}

int test2(int b)
{
    return b;
}

swap(&test1, &test2);

Complete compiling working program

#include <stdio.h>
#include <stdlib.h>

typedef int (* func_pt)(int);

func_pt a, b;

int test1(int a)
{
    printf("test1\n");
    return 1;
}

int test2(int a)
{
    printf("test2\n");
    return 2;
}

void swap(func_pt * a, func_pt * b)
{
    func_pt tmp = *b;

    *b = *a;
    *a = tmp;
}

int main(void)
{
    a = &test1;
    b = &test2;

    printf("before\n");
    a(1);
    b(1);

    swap(&a, &b);

    printf("after\n");
    a(1);
    b(2);

    return 0;

}

Output:

before
test1
test2
after
test2
test1

Some people do not try it by themselves, just say it absurd.So I give you a example.

查看更多
登录 后发表回答