Is it possible to swap C functions?

2019-02-14 20:29发布

问题:

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.

回答1:

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.



回答2:

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);


回答3:

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:

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:

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.